Группировка тестов 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) может иметь поддержку для запуска всех тестов, содержащихся в данном пакете.