В своем последнем сообщении в блоге я посоветовал время от времени пересматривать свое мнение, поскольку мир ИТ быстро меняется. То, что было правдой пару лет назад, в наши дни может быть совершенно неверным, и вы, вероятно, не захотите основывать свои решения на устаревших данных. На этой неделе я хотел бы последовать своему совету.
Один из моих первых постов был в защиту TestNG против JUnit. В этом посте я упомянул несколько функций, которых не хватало JUnit:
- Отсутствие параметризации
- Никакой группировки
- Нет заказа метода тестирования
Поскольку JUnit 5 уже некоторое время отсутствует, давайте проверим, исправил ли он эти проблемы.
Параметризация
Я написал первый пост в 2008 году, и я думаю, что в то время JUnit был доступен в версии 3. Давайте перейдем непосредственно к версии 4: JUnit действительно предлагал параметризацию. Вот фрагмент из их вики:
@RunWith(Parameterized.class) // 1
public class FibonacciTest {
private int fInput; // 2
private int fExpected; // 2
public FibonacciTest(int input, int expected) { // 3
this.fInput = input;
this.fExpected = expected;
}
@Parameters // 4
public static Collection- Установите бегунка
- Определите атрибут для каждого параметра теста
- Определите конструктор с параметрами для каждого параметра
- Аннотировать метод параметров
- Реализуйте метод параметров. Он должен быть
статическими возвращатьКоллекцию<Объект[]>
Вот как вы могли бы добиться того же с помощью тестирования:
public class FibonacciTest {
@DataProvider // 1
public Object[][] data() { // 2
return new Object[][] {
{ 0, 0 }, { 1, 1 }, { 2, 1 }, { 3, 2 }, { 4, 3 }, { 5, 5 }, { 6, 8 }
};
}
@Test(dataProvider = "data") // 3
public void test(String input, String expected) {
assertEquals(input, expected);
}
}
- Аннотировать с помощью
@dataProvider - Должен возвращать
Объект[][], не обязательно бытьстатическим @Тестуказывает на метод предоставления данных –данные
В версии 5 JUnit предлагает аннотацию @Parameterizedtest . Параметризованные тесты ожидают по крайней мере одного источника параметров, также указанного в аннотации. Доступно несколько источников:
| Примитивы, Строка и класс | @Источник ценности |
| Выделенное перечисление | @Источник ценности |
| Конкретный метод. Метод должен быть статическим и возвращать поток | @Источник методов |
| Многозначные данные в формате CSV | @Источник методов |
| Внешний сторонний файл | @CSV-файловый источник |
| Выделенный класс, реализующий Поставщика аргументов | @Источник аргументов |
В то время как подход к тестированию может охватывать все варианты использования, возможности множественной конфигурации JUnit 5 более индивидуальны.
Группировка
Опять же, в первоначальном сообщении упоминается, что с JUnit 3 нельзя запускать только их подмножество. JUnit 4 предоставляет два ортогональных способа группирования тестов. Первый – это наборы тестов:
public class A {
@Test
public void a() {}
@Test
public void a2() {}
}
public class B {
@Test
public void b() {}
}
@SuiteClasses( { A.class, B.class })
public class ABSuite {}
С этого момента вы можете запустить AB Suite для запуска обоих A и B . Для более детальных целей вы также можете использовать категории .
public interface Fast {}
public interface Slow {}
public class A {
@Test
public void a() {}
@Category(Slow.class)
@Test
public void b() {}
}
@Category({Slow.class, Fast.class})
public class B {
@Test
public void c() {}
}
Вот как вы можете запускать только нужные категории с помощью Maven:
mvn test -Dtest.categories=Fast
Тестирование очень похоже на категории (или наоборот).:
public class A {
@Test
public void a() {}
@Test(groups = "slow")
public void b() {}
}
@Test(groups = { "slow", "fast" })
public class B {
@Test
public void c() {}
}
mvn test -Dgroups=fast
JUnit 5 изменил свой подход с помощью аннотации @Tag . Теги – это метки, которыми вы помечаете свой класс. Затем вы можете отфильтровать теги, которые хотите запустить во время выполнения теста:
public class A {
@Test
public void a() {}
@Test
@Tag("slow")
public void b() {}
}
@Tag("fast")
@Tag("slow")
public class B {
@Test
public void c() {}
}
Обе платформы реализуют аналогичное выполнение подмножества тестов.
Заказ метода испытания
Этот момент является наиболее спорным из всех, потому что JUnit проистекает из модульного тестирования . В модульном тестировании тесты должны быть независимыми друг от друга. По этой причине вы можете запускать их параллельно.
К сожалению, в тот или иной момент вам, вероятно, потребуется провести некоторое интеграционное тестирование. Мой пример перехода – это приложение для магазина электронной коммерции. мы хотим протестировать сценарий оформления заказа со следующими шагами:
- Пользователи могут просматривать каталог товаров
- Они могут класть товары в свою корзину
- Они могут перейти на страницу оформления заказа
- Наконец-то они могут заплатить
Без заказа метода тестирования вы получаете гигантский метод тестирования. Если тест провалился, то с первого взгляда невозможно определить, где он провалился. Вам нужно детализировать и надеяться, что журнал содержит соответствующую информацию.
При упорядочении методов тестирования можно реализовать по одному методу на шаг и упорядочить их соответствующим образом. Когда какой-либо метод дает сбой, вы знаете, на каком шаге он сработал – при условии, что вы дали методу соответствующее имя.
По этой причине JUnit не подходил для интеграционного тестирования. Было бы неразумно использовать JUnit для модульного тестирования и тестирования для интеграционного тестирования в одном проекте. Учитывая, что тестирование могло сделать все, что мог JUnit, это самая важная причина, по которой я предпочел первое второму.
Тестирование реализует упорядочение путем обеспечения зависимостей между методами тестирования. Он вычисляет ориентированный ациклический граф зависимых методов во время выполнения и запускает методы соответствующим образом. Вот пример, относящийся к электронной коммерции выше:
public class CheckoutIT {
@Test
public void browseCatalog() {}
@Test(dependsOnMethods = { "browseCatalog" })
public void addProduct() {}
@Test(dependsOnMethods = { "addProduct" })
public void checkout() {}
@Test(dependsOnMethods = { "checkout" })
public void pay() {}
}
JUnit 5 предоставляет несколько способов реализации упорядочения методов тестирования:
| Никакого порядка | Случайный |
| Буквенно-цифровое название метода | Имя метода |
| Буквенно-цифровое отображаемое имя, задаваемое @DisplayName для каждого метода тестирования | Отображаемое имя |
| Порядок, установленный @Order для каждого метода тестирования | Аннотация к заказу |
Можно реализовать один и тот же сценарий тестирования электронной коммерции, например, следующим образом:
@TestMethodOrder(OrderAnnotation.class) // 1
public class CheckoutIT {
@Test
@Order(1) // 2
public void browseCatalog() {}
@Test
@Order(2) // 2
public void addProduct() {}
@Test
@Order(3) // 2
public void checkout() {}
@Test
@Order(4) // 2
public void pay() {}
}
- Определите порядок на основе
@Order - Установите порядок для каждого метода
Тестирование реализует заказ через/| DAG , JUnit напрямую. Подход к тестированию более гибкий, поскольку он позволяет среде выполнения запускать некоторые методы параллельно, но JUnit выполняет эту работу.
Вывод
До сих пор я предпочитал тестирование из-за плохого дизайна параметризации и, что более важно, полного отсутствия упорядочения. Версия 5 JUnit исправляет обе проблемы. Более того, его реализация предлагает множество возможностей настройки.
Все еще есть области, где тестирование блистает:
- У него более богатый жизненный цикл
- Для интеграционного тестирования его возможности определения зависимостей между тестами являются огромным преимуществом
- Кроме того, мне не особенно нравится комментировать свои методы с помощью
staticдля параметризованных тестов JUnit.
Тем не менее, учитывая, что экосистема JUnit гораздо более развита, я думаю, что переключусь на JUnit для новых проектов и снова проведу переоценку через несколько лет.
Идти дальше:
- Война модульных тестов: JUnit против TestNG
- Быстрое сравнение JUnit и TestNG
- Руководство пользователя JUnit 5
- Документация по тестированию
Первоначально опубликовано на Фанат Java 19 сентября th , 2021
Оригинал: “https://dev.to/nfrankel/reassessing-testng-vs-junit-55f”