Написание тестов Java с поставщиками данных

В настоящее время я делаю свой первый Java-проект и хотел бы полностью его реализовать. Я использую JUnit для написания тестов. Очевидно, JUnit не обеспечивает поддержку поставщиков данных, что делает довольно неудобным тестирование одного и того же метода с 20 различными версиями аргумента. Какой самый популярный / стандартный инструмент тестирования для Java поддерживает поставщиков данных? Я сталкивался с TestNG, но понятия не имею, насколько он популярен или как его сравнивают с альтернативами.

Если есть способ получить такое поведение - хороший способ использования JUnit, то это также может сработать.

6 ответов

Решение

JUnit 4 имеет параметризованный тест, который делает то же самое, что и провайдеры данных php

@RunWith(Parameterized.class)
public class MyTest{ 
     @Parameters
    public static Collection<Object[]> data() {
           /*create and return a Collection
             of Objects arrays here. 
             Each element in each array is 
             a parameter to your constructor.
            */

    }

    private int a,b,c;


    public MyTest(int a, int b, int c) {
            this.a= a;
            this.b = b;
            this.c = c;
    }

    @Test
    public void test() {
          //do your test with a,b
    }

    @Test
    public void testC(){
        //you can have multiple tests 
        //which all will run

        //...test c
    }
}

Мои коллеги из нашей компании написали свободно доступный DataProvider в стиле TestNG для JUnit, который вы можете найти https://github.com/TNG/junit-dataprovider.

Мы используем его в очень крупных проектах, и он прекрасно работает для нас. У него есть некоторые преимущества перед JUnit Parameterized так как это уменьшит накладные расходы отдельных классов, и вы также сможете выполнять отдельные тесты.

Пример выглядит примерно так

@DataProvider
public static Object[][] provideStringAndExpectedLength() {
    return new Object[][] {
        { "Hello World", 11 },
        { "Foo", 3 }
    };
}

@Test
@UseDataProvider( "provideStringAndExpectedLength" )
public void testCalculateLength( String input, int expectedLength ) {
    assertThat( calculateLength( input ) ).isEqualTo( expectedLength );
}

Редактирование: начиная с v1.7, он также поддерживает другие способы предоставления данных (строки, списки) и может встроить поставщика, так что отдельный метод не обязательно нужен.

Полный рабочий пример можно найти на странице руководства на github. Он также имеет несколько дополнительных функций, таких как сбор провайдеров в служебных классах и доступ к ним из других классов и т. Д. Страница руководства очень подробная, я уверен, что вы найдете ответы на все вопросы там.

В зависимости от ваших потребностей в гибкости и читабельности, вы можете выбрать Parameterized - встроенный вариант junit, описанный dkatzel. Другими вариантами являются внешние джунит-бегуны, предоставляемые внешними библиотеками, такими как zohhak, которые мы вам сделаем

 @TestWith({
        "clerk,      45'000 USD, GOLD",
        "supervisor, 60'000 GBP, PLATINUM"
    })
    public void canAcceptDebit(Employee employee, Money money, ClientType clientType) {
        assertTrue(   employee.canAcceptDebit(money, clientType)   );
    }

или junitParams с немного другой функциональностью. просто выберите то, что подходит вам больше всего

Вы можете использовать JUnit 5 ParameterizedTest. Вот пример из https://www.petrikainulainen.net/programming/testing/junit-5-tutorial-writing-parameterized-tests/:

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;

import java.util.stream.Stream;

import static org.junit.jupiter.api.Assertions.assertEquals;

@DisplayName("Should pass the method parameters provided by the sumProvider() method")
class MethodSourceExampleTest {

    @DisplayName("Should calculate the correct sum")
    @ParameterizedTest(name = "{index} => a={0}, b={1}, sum={2}")
    void sum(int a, int b, int sum) {
        assertEquals(sum, a + b);
    }

    private static Stream<Arguments> sumProvider() {
        return Stream.of(
                Arguments.of(1, 1, 2),
                Arguments.of(2, 3, 5)
        );
    }
}

Параметры теста можно загрузить из аннотации, метода или даже файла CSV.

Вот еще один вариант. Вам не нужно использовать Google Guava, это только моя реализация.

Это использует тот же @Parameters как ответ @dkatzel, но вместо класса, принимающего аргументы, @Parameters аннотация применяется к определенным методам тестирования, поэтому вы можете выбирать, какие методы используют этот набор аргументов.

import java.util.Collection;

import com.google.common.collect.ImmutableList;

import junitparams.JUnitParamsRunner;
import junitparams.Parameters;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;

@RunWith(JUnitParamsRunner.class)
public class FrobTester {
    @SuppressWarnings("unused")
    private Collection validfrobAndGorpValues() {
        return ImmutableList.of(
            new Object[] {"frob28953", 28953},
            new Object[] {"oldfrob-189-255", 1890255}
        );
    }

    @Test
    @Parameters(method = "validfrobAndGorpValues")
    public void whenGivenFrobString_thenGorpIsCorrect(
        String frobString,
        int expectedGorpValue
    ) {
        Frob frob = new Frob(frobString);
        Assert.assertEquals(expectedGorpValue, frob.getGorpValue());
    }
}

Вы можете использовать платформу https://genthz.org/ для генерации тестовых данных.

Образец:

      public class User {
    private Person person;

    private String login;

    private String password;
}

public class Person {
    protected String name;

    protected String lastName;

    protected Date birthday;

    private IdCard idCard;
}

User value = new DashaDsl() {
        {
//          Generate value for name fiedl of Persone class.
            path("person/name")
//              Set custom instance builder for field name of Person class.
                .simple(ctx -> "Alex");
        }
//      Use defaults configuration such as int, java.lang.Stirng and etc.
        }.def()
//      Get ObjectFactory
        .objectFactory()
//      Generate Person class object
        .get(User.class);

Другие вопросы по тегам