Группировка тестов JUnit
Есть ли способ сгруппировать тесты в JUnit, чтобы я мог запускать только некоторые группы?
Или можно аннотировать некоторые тесты, а затем глобально их отключить?
Я использую JUnit 4, я не могу использовать TestNG.
edit: @RunWith и @SuiteClasses отлично работают. Но можно ли так аннотировать только некоторые тесты в тестовом классе? Или мне нужно аннотировать весь тестовый класс?
Ответы
Ответ 1
Хотите ли вы сгруппировать тесты внутри тестового класса или же вы хотите сгруппировать тестовые классы? Я собираюсь предположить последнее.
Это зависит от того, как вы проводите свои тесты. Если вы запускаете их в Maven, можно точно указать, какие тесты вы хотите включить. Для этого см. достоверную документацию Maven.
В целом, однако, я делаю то, что у меня есть дерево наборов тестов. Набор тестов в JUnit 4 выглядит примерно так:
@RunWith(Suite.class)
@SuiteClasses({SomeUnitTest1.class, SomeUnitTest2.class})
public class UnitTestsSuite {
}
Итак, может быть, у меня есть FunctionTestsSuite и UnitTestsSuite, а затем AllTestsSuite, который включает в себя два других. Если вы запустите их в Eclipse, вы получите очень хороший иерархический вид.
Проблема с этим подходом в том, что он довольно утомителен, если вы хотите разрезать тесты несколькими способами. Но это все еще возможно (вы можете, например, иметь один набор наборов, которые срезают на основе модуля, а затем другой срез по типу теста).
Ответ 2
JUnit 4.8 поддерживает группировку:
public interface SlowTests {}
public interface IntegrationTests extends SlowTests {}
public interface PerformanceTests extends SlowTests {}
А потом...
public class AccountTest {
@Test
@Category(IntegrationTests.class)
public void thisTestWillTakeSomeTime() {
...
}
@Test
@Category(IntegrationTests.class)
public void thisTestWillTakeEvenLonger() {
...
}
@Test
public void thisOneIsRealFast() {
...
}
}
И, наконец,
@RunWith(Categories.class)
@ExcludeCategory(SlowTests.class)
@SuiteClasses( { AccountTest.class, ClientTest.class })
public class UnitTestSuite {}
Взят отсюда: https://community.oracle.com/blogs/johnsmart/2010/04/25/grouping-tests-using-junit-categories-0
Кроме того, сам Arquillian поддерживает группировку:https://github.com/weld/core/blob/master/tests-arquillian/src/test/java/org/jboss/weld/tests/Categories.java
Ответ 3
Чтобы справиться с глобальным отключением их, JUnit (4.5+) имеет два способа. Один из них - использовать новый метод takeThat. Если вы поместите это в @BeforeClass (или @Before) тестового класса, и если условие завершится неудачно, оно проигнорирует тест. В этом состоянии вы можете поместить системное свойство или что-то еще, что можно включить или отключить глобально.
Другой альтернативой является создание пользовательского бегуна, который понимает глобальное свойство и делегирует соответствующий бегун. Этот подход намного более хрупкий (поскольку внутренние бегуны JUnit4 нестабильны и могут быть изменены с момента выпуска на выпуск), но он имеет то преимущество, что может быть унаследован по иерархии классов и переопределен в подклассе. Это также единственный реалистичный способ сделать это, если вам нужно поддерживать устаревшие классы JUnit38.
Вот некоторый код, чтобы сделать пользовательский Runner. Относительно того, что может сделать getAppropriateRunnerForClass, способ, которым я реализовал это, состоял в том, чтобы иметь отдельную аннотацию, которая сообщает пользовательскому бегуну, с чем работать. Единственной альтернативой была какая-то очень хрупкая скопированная копия из кода JUnit.
private class CustomRunner implements Runner
private Runner runner;
public CustomRunner(Class<?> klass, RunnerBuilder builder) throws Throwable {
if (!isRunCustomTests()) {
runner = new IgnoredClassRunner(klass);
} else {
runner = getAppropriateRunnerForClass(klass, builder);
}
public Description getDescription() {
return runner.getDescription();
}
public void run(RunNotifier notifier) {
runner.run(notifier);
}
}
EDIT: Тег @RunWith работает только для целого класса. Один из способов обойти это ограничение состоит в том, чтобы переместить методы тестирования в статический внутренний класс и аннотировать это. Таким образом, у вас есть преимущество аннотации с организацией класса. Но делать это не поможет с тегами @Before или @BeforeClass, вам придется воссоздать их во внутреннем классе. Он может вызывать метод внешнего класса, но он должен будет иметь свой собственный метод как крючок.
Ответ 4
Попробуйте JUnit Test Groups. Из документации:
@TestGroup("integration")
public class MyIntegrationTest {
@ClassRule
public static TestGroupRule rule = new TestGroupRule();
...
}
- Выполните простую тестовую группу: -Dtestgroup = integration
- Выполнять несколько тестовых групп: -Dtestgroup = group1, group2
- Выполните все тестовые группы: -Dtestgroup = all
Ответ 5
В JUnit 5 вы можете объявить @Tag
для фильтрации тестов на уровне класса или метода; аналогично тестовым группам в TestNG или категориям в JUnit 4
От Javadoc:
теги используются для фильтрации, какие тесты выполняются для данного плана тестирования. Например, команда разработчиков может пометить тесты такими значениями, как "быстрый", "медленный", "ci-сервер" и т.д., А затем предоставить список тегов, которые будут использоваться для текущего плана тестирования, потенциально зависящего от текущего среда.
Например, вы можете объявить тестовый класс с "slow"
@Tag
который будет унаследован для всех методов, и при необходимости переопределить его для некоторых методов:
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
@Tag("slow")
public class FooTest{
//
@Test
void loadManyThings(){
...
}
@Test
void loadManyManyThings(){
...
}
@Test
@Tag("fast")
void loadFewThings(){
...
}
}
Вы можете применить ту же логику для других тестовых классов.
Таким образом, тестовые классы (и методы тоже) принадлежат определенному тегу.
В качестве хорошей практики вместо копирования и вставки @Tag("fast")
и @Tag("slow")
в тестовые классы вы можете создавать собственные составные аннотации.
Например:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.junit.jupiter.api.Tag;
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Tag("slow")
public @interface Slow {
}
и использовать его как:
@Test
@Slow
void slowProcessing(){
...
}
Чтобы включить или отключить тест, помеченный определенным тегом во время выполнения текста, вы можете положиться на документацию maven-surefire-plugin:
Чтобы включить теги или выражения тегов, используйте groups
.
Чтобы исключить теги или выражения тегов, используйте либо excludedGroups
.
Просто настройте в вашем pom.xml плагин в соответствии с вашими требованиями (пример документа):
<build>
<plugins>
...
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.0</version>
<configuration>
<groups>acceptance | !feature-a</groups>
<excludedGroups>integration, regression</excludedGroups>
</configuration>
</plugin>
</plugins>
</build>
Для информации документация цели теста не обновляется.
Ответ 6
Вы можете создать тестер Suite объекты, содержащие группы тестов. Кроме того, ваша IDE (например, Eclipse) может иметь поддержку для запуска всех тестов, содержащихся в данном пакете.
Ответ 7
Вы можете использовать Test Suite (http://qaautomated.blogspot.in/2016/09/junit-test-suits-and-test-execution.html), или вы можете использовать категории Junit (http://qaautomated.blogspot.in/2016/09/junit-categories.html) для эффективной группировки тестовых примеров.