Начиная с версии 4.8 JUnit включает в себя возможность, которая уже давно радовала пользователей TestNG — возможность группировать тесты для выполнения. Группировка тестов в JUnit осуществляется с помощью, так называемых, категорий. Каждая категория должна представлять собой интерфейс или класс. Но так как они используются исключительно для маркировки тестов, то чаще всего категории представляются именно в виде интерфейсов. Например:
public interface UnitTests {}
При создании категорий можно также использовать наследование, это даст дополнительную гибкость при организации тестов:
public interface Category1 {} public interface Category2 extends Category1 {}
В случае использования наследования, во время запуска на выполнение категории Category1 будут также выполнены все унаследованные классы, т.е. в данном случае Category2.
Созданными категориями можно маркировать тестовые классы или непосредственно тестовые методы:
@Category(Category1.class) public class SomeTest { @Test public void testMethod1() { ... } @Test public void testMethod2() { .... } }
или
public class SomeTest { @Test @Category(Category2.class) public void testMethod1() { ... } @Test @Category({Category1.class, Category3.class}) public void testMethod2() { .... } }
Категорию нельзя применить к Suite, это не даст никакого эффекта.
Теперь самое интересное — запуск категорий на выполнение. Сделать это можно как с помощью Suite, так и с помощью Maven.
Suite
Напомню, что в JUnit4 Suite — это по существу пустой аннотированный класс. Чтобы запустить на выполнение тесты в определенной категории, нужно использовать аннотацию @RunWith (Categories.class) и с помощью другой аннотации @IncludeCategory указать какую именно категорию тестов нужно выполнить:
@RunWith(Categories.class) @IncludeCategory(Unit.class) @SuiteClasses( { Test1.class, Test2.class }) public class UnitTestSuite {}
Используя аннотацию @ExcludeCategory можно инвертировать запуск и выполнить все тесты кроме категории, указанной в аннотации:
@RunWith(Categories.class) @ExcludeCategory(Unit.class) @SuiteClasses( { Test1.class, Test2.class }) public class IntegrationTestSuite {}
Аннотации @IncludeCategory и @ExcludeCategory можно использовать одновременно. Но нельзя объявлять одну и туже аннотацию несколько раз, также как и нельзя указать несколько категорий в одной аннотации. Поэтому запуск тестов из нескольких категорий можно урегулировать только через их наследование. Что опять же указывает на плюс использования интерфейсов, в отличии от классов интерфейсы позволяют выполнять множественное наследование. Скажем, Ваши тесты промаркированы следующими категориями:
public interface Category1 {} public interface Category2 {} public interface Category3 {} public interface Category4 {}
и Вы хотите запускать тесты из категорий попарно Category1, Category2 и Category1,Category3. Для этого нужно сделать следующее:
public interface Category12 {} public interface Category13 {} public interface Category1 extends Category12,Category13 {} public interface Category2 extends Category12 {} public interface Category3 extends Category13 {} public interface Category4 {}
Теперь категории Category12 и Category13 можно передавать в аннотацию @IncludeCategory. Создание таких родительских категорий, конечно, отнимает время, зато позволяет не изменять существующую маркировку тестовых методов или классов.
Правда, с увеличением количества классов в Suite и возможных вариантов запуска, конфигурация получается достаточно громоздкой. И самый большой недостаток, на мой взгляд, это добавление тестовых классов в Suite, об этом нужно постоянно помнить при создании новых классов.
Maven
Запуск категорий тестов с помощью Maven представляет собой более гибкий и удобный в использовании вариант. Для этого понадобится настроить maven-surefire-plugin:
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>2.12</version> <dependencies> <dependency> <groupId>org.apache.maven.surefire</groupId> <artifactId>surefire-junit47</artifactId> <version>2.12</version> </dependency> </dependencies> <configuration> <groups>com.example.cat.Category1</groups> </configuration> </plugin>
Внутренняя зависимость в плагине surefire-junit47
обязательно должна присутствовать, иначе Maven будет игнорировать аннотации @Category.
Для того, чтобы исключить запуск каких-либо категорий, используется свойство excludedGroups
:
<configuration> <excludedGroups>com.example.cat.Category2</excludedGroups> </configuration>
Чтобы указать несколько категорий для запуска достаточно внести их через запятую:
<configuration> <groups>com.example.cat.Category1,com.example.cat.Category2</groups> </configuration>
При запуске с помощью Maven наследование среди категорий не учитывается, все категории должны быть указаны явно. В связи с этим использование одновременно свойств groups
и excludedGroups
не имеет смысла, на выполнение будут запущены только тесты категорий, перечисленных в groups
.
Тесты завершатся неудачей в том случае, если абсолютно все тестовые методы промаркированы категорией, которая была исключена. Чтобы избежать такого, лучше маркировать исключаемой категорией классы.
Спасибо за статью.
А запуск в jenkins определенный категории как происходит? Через этот параметр -DtestName=$testName, где testName = com.example.cat.Category2?
Нет
Если Вы имеете ввиду свойство testname из этой статьи http://internetka.in.ua/thucydides-jenkins/, то по аналогии с ним можно ввести свое свойство для значения
<groups>com.example.cat.Category1</groups>
в surefire-junit47 и потом его задавать в командной строке.А какие изменения нужно в pom файле сделать, testName нужно убрать?
${testName}
Эти теги нужны, если мы используем category?
Можно не убирать, тесты будут выполняться по пересечению значений этих двух свойств.
Нужно Вам свойство в проекте или нет — это сами решайте.
Почитайте как работать с мавеном, это поможет Вам в дальнейшем.
У меня выдает ошибку, даже если не использовать запуск с параметрами.
Results :
Tests in error:
initializationError(org.junit.runner.manipulation.Filter): No tests found matching *veeam.com.test.Category.Web_Shop from org.ju
nit.runner.Request$1@1286929