使用数据提供程序编写 Java 测试

IT小君   2021-12-05T00:20:29

我目前正在做我的第一个 Java 项目并且喜欢完全 TDD 它。我正在使用 JUnit 来编写测试。显然 JUnit 不提供对data providers 的支持,这使得用 20 个不同版本的参数测试相同的方法变得相当烦人。支持数据提供程序的最流行/标准的 Java 测试工具是什么?我遇到了TestNG,但不知道它有多受欢迎,或者它与替代品相比如何。

如果有一种方法是使用 JUnit 来获得这种行为的好方法,那么这也可能有效。

评论(5)
IT小君

我公司的同事为 JUnit 编写了一个可免费使用的 TestNG 风格的 DataProvider,你可以在 github (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 的手册页上找到完整的工作示例。它还具有更多功能,例如收集实用程序类中的提供者并从其他类访问它们等。手册页非常详细,我相信您会在那里找到任何问题的答案。

2021-12-05T00:20:29   回复
IT小君

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
    }
}
2021-12-05T00:20:30   回复
IT小君

根据您在灵活性和可读性方面的需求,您可以选择Parameterized- junit 的内置选项,由 dkatzel 描述。其他选项是由外部库(如zohhak )提供的外部 junit运行器,您可以这样做:

 @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具有一些不同的功能。只选择最适合你的

2021-12-05T00:20:30   回复
IT小君

您可以使用 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}")
    @MethodSource("sumProvider")
    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 文件加载测试参数。

2021-12-05T00:20:30   回复
IT小君

这是另一种选择。您不必使用 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());
    }
}
2021-12-05T00:20:30   回复