В своем последнем сообщении в блоге я посоветовал время от времени пересматривать свое мнение, поскольку мир ИТ быстро меняется. То, что было правдой пару лет назад, в наши дни может быть совершенно неверным, и вы, вероятно, не захотите основывать свои решения на устаревших данных. На этой неделе я хотел бы последовать своему совету.
Один из моих первых постов был в защиту 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”