Рубрики
Без рубрики

Переоценка TestNG по сравнению с Junit

В своем последнем посте в блоге я посоветовал время от времени пересматривать свое мнение по мере того, как меняется мир ИТ… Помеченный java, junit, testng.

В своем последнем сообщении в блоге я посоветовал время от времени пересматривать свое мнение, поскольку мир ИТ быстро меняется. То, что было правдой пару лет назад, в наши дни может быть совершенно неверным, и вы, вероятно, не захотите основывать свои решения на устаревших данных. На этой неделе я хотел бы последовать своему совету.

Один из моих первых постов был в защиту 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 data() {             // 5
        return Arrays.asList(new Object[][] {
            { 0, 0 }, { 1, 1 }, { 2, 1 }, { 3, 2 }, { 4, 3 }, { 5, 5 }, { 6, 8 }
        });
    }

    @Test
    public void test() {
        assertEquals(fExpected, Fibonacci.compute(fInput));
    }
}
  1. Установите бегунка
  2. Определите атрибут для каждого параметра теста
  3. Определите конструктор с параметрами для каждого параметра
  4. Аннотировать метод параметров
  5. Реализуйте метод параметров. Он должен быть статическим и возвращать Коллекцию<Объект[]>

Вот как вы могли бы добиться того же с помощью тестирования:

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);
    }
}
  1. Аннотировать с помощью @dataProvider
  2. Должен возвращать Объект[][] , не обязательно быть статическим
  3. @Тест указывает на метод предоставления данных – данные

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

К сожалению, в тот или иной момент вам, вероятно, потребуется провести некоторое интеграционное тестирование. Мой пример перехода – это приложение для магазина электронной коммерции. мы хотим протестировать сценарий оформления заказа со следующими шагами:

  1. Пользователи могут просматривать каталог товаров
  2. Они могут класть товары в свою корзину
  3. Они могут перейти на страницу оформления заказа
  4. Наконец-то они могут заплатить

Без заказа метода тестирования вы получаете гигантский метод тестирования. Если тест провалился, то с первого взгляда невозможно определить, где он провалился. Вам нужно детализировать и надеяться, что журнал содержит соответствующую информацию.

При упорядочении методов тестирования можно реализовать по одному методу на шаг и упорядочить их соответствующим образом. Когда какой-либо метод дает сбой, вы знаете, на каком шаге он сработал – при условии, что вы дали методу соответствующее имя.

По этой причине 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() {}
}
  1. Определите порядок на основе @Order
  2. Установите порядок для каждого метода

Тестирование реализует заказ через/| DAG , JUnit напрямую. Подход к тестированию более гибкий, поскольку он позволяет среде выполнения запускать некоторые методы параллельно, но JUnit выполняет эту работу.

Вывод

До сих пор я предпочитал тестирование из-за плохого дизайна параметризации и, что более важно, полного отсутствия упорядочения. Версия 5 JUnit исправляет обе проблемы. Более того, его реализация предлагает множество возможностей настройки.

Все еще есть области, где тестирование блистает:

  • У него более богатый жизненный цикл
  • Для интеграционного тестирования его возможности определения зависимостей между тестами являются огромным преимуществом
  • Кроме того, мне не особенно нравится комментировать свои методы с помощью static для параметризованных тестов JUnit.

Тем не менее, учитывая, что экосистема JUnit гораздо более развита, я думаю, что переключусь на JUnit для новых проектов и снова проведу переоценку через несколько лет.

Идти дальше:

Первоначально опубликовано на Фанат Java 19 сентября th , 2021

Оригинал: “https://dev.to/nfrankel/reassessing-testng-vs-junit-55f”