Могу ли я избежать запуска тестов junit дважды в eclipse при использовании TestSuite?
Мне нужно выполнить инициализацию для каждого набора (запуск веб-сервера). Он работает нормально, за исключением того, что когда я запускаю все тесты в моем проекте в Eclipse, мои тесты запускаются дважды. Мой набор тестов выглядит примерно так:
@RunWith(Suite.class)
@Suite.SuiteClasses({
SubtestOne.class,
SubtestTwo.class
})
public class TestSuite
{
[...]
}
public class SubtestOne
{
@Test public void testOne() { [...] }
}
public class SubtestTwo
{
@Test public void testTwo() { [...] }
}
Когда я запускаю все тесты в проекте в eclipse, это заставляет плагин junit запускать тесты дважды так:
- SubtestOne
- SubtestTwo
- Тестирование
- SubtestOne
- SubtestTwo
Можно ли заставить "запускать все тесты в проекте", чтобы не запускать под-тесты дважды? Я хочу, чтобы мои суб-тесты запускались только как часть пакета.
4 ответа
Я понимаю, что это было задано более 5 лет назад, но, как многие проголосовали против вопроса, я подумал, что я все еще согласен с решением. Пропустите прямо до конца, если вы просто хотите решение; Прочитайте весь текст, если вы тоже хотите это понять;-)
Прежде всего, действительно возможно гарантировать, что определенный тестовый класс JUnit запускается только внутри набора тестов. Кроме того, не имеет значения, хотите ли вы запустить этот набор тестов в Eclipse (как здесь сказано) или в любом другом инструменте или среде; это действительно чистый вопрос JUnit по большей части.
Прежде чем я набросаю решение, было бы неплохо вернуться к тому, что именно здесь происходит. Все тесты JUnit должны быть видимыми и инстанцируемыми, чтобы их могли воспринимать среда JUnit и ее различные исполнители. Это также относится к наборам тестов и отдельным тестам, которые являются частью набора тестов. Как следствие, если JUnit выбирает набор тестов, он также выбирает отдельные тесты, и все тесты в наборе будут выполняться дважды, один раз по отдельности и один раз как часть набора.
Итак, хитрость, если хотите, состоит в том, чтобы JUnit не мог подбирать отдельные тесты, в то же время имея возможность создавать и выполнять их как часть пакета.
Одна вещь, которая приходит на ум, - сделать классы тестов статичными внутренними классами, вложенными в набор тестов. Тем не менее, вложенные классы по-прежнему должны быть общедоступными (в противном случае они также не могут быть запущены в комплекте), и если они являются открытыми классами, они также будут выбираться индивидуально, несмотря на то, что они вложены в открытый класс пакета. Однако JUnit не будет пытаться запускать тестовые классы, которые не считаются видимыми. Итак, вложенных тестовых классов внутри закрытого класса, вероятно, было бы достаточно, чтобы скрыть их, но мы не можем сделать класс пакета закрытым, потому что тогда JUnit не выполнит его. Однако мы можем вложить отдельные тесты в другой непубличный класс, который вложен в набор тестов, что приводит нас к решению этой головоломки:
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
@RunWith(Suite.class)
@SuiteClasses({AllTests.InSuiteOnly.Test1.class, AllTests.InSuiteOnly.Test2.class})
public class AllTests
{
static class InSuiteOnly
{
public static class Test1
{
@Test
public void test1()
{
//...
}
}
public static class Test2
{
@Test
public void test2()
{
//...
}
}
}
}
Многие люди, вероятно, будут возражать против всех тестов, которые должны находиться внутри одного исходного файла. Что если я хочу поддерживать отдельные тестовые классы JUnit, которые не выполняются сами по себе, а выполняются внутри набора тестов? Простое решение состоит в том, чтобы сделать отдельные тестовые классы абстрактными (public/non-public не имеет значения) так, чтобы JUnit не выполнял их, а внутри набора тестов мы просто используем конкретные подклассы исходных абстрактных тестовых классов:
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
@RunWith(Suite.class)
@SuiteClasses({AllTests.InSuiteOnly.SuiteTest1.class, AllTests.InSuiteOnly.SuiteTest2.class})
public class AllTests
{
static class InSuiteOnly
{
public static class SuiteTest1 extends Test1 {}
public static class SuiteTest2 extends Test2 {}
}
}
abstract class Test1
{
@Test
public void test1()
{
//...
}
}
abstract class Test2
{
@Test
public void test2()
{
//...
}
}
Эта схема работает с Maven, Eclipse и всеми другими средами, которые либо непосредственно используют бегуны JUnit, либо реализуют свои собственные бегуны, которые точно следуют исходному поведению и семантике JUnit.
Нет, тестовый класс всегда будет запускаться напрямую, а затем через "ссылку" в наборе. Это как и ожидалось.
Один обходной путь может быть установлен в конфигурации запуска, чтобы запускать тесты только из пакета, который содержит ваши комплекты. Откройте конфигурацию запуска и выберите Run all tests in the selected project, package or source folder
затем нажмите Search...
и выберите пакет.
Вам нужен номер в первую очередь? в зависимости от того, когда вы щелкнете по кнопке run all (класс, пакет или src/test/java), будут выполнены все базовые тесты. Так какой смысл иметь номер?
Есть решение, оно немного хитрое, но оно может легко решить вашу проблему: создайте один класс набора и включите в него все ваши классы набора. Затем вы можете использовать этот класс для запуска всех ваших тестов.
@RunWith(Suite.class)
@Suite.SuiteClasses({
AXXSuite.class,
BXXSuite.class,
CXXSuite.class
})
public class AllSuites {
}
У меня есть идея для вас. На самом деле вы не хотите запускать эти тестовые сценарии как отдельные тестовые примеры. Вы можете сделать следующее.
Пометьте тестовые случаи аннотацией @RunWith(DoNothingRunner.class)
Выполнить DoNothingRunner следующим образом:
public class DoNothingRunner extends Runner {
public Description getDescription() {
return "do nothing";
}
public void run(RunNotifier notifier) {
// indeed do nothing
}
}
Я не пробовал это лично, но я надеюсь, что это будет работать.