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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19203730/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 15:00:27  来源:igfitidea点击:

Writing Java tests with data providers

javatestingjunit

提问by Jeroen De Dauw

I'm currently doing my first Java project and like to fully TDD it. I'm using JUnit for writing the tests. Apparently JUnit does not provide support for data providers, which makes it rather annoying to test the same method with 20 different versions of an argument. What is the most popular/standard testing tool for Java that does support data providers? I came across TestNG, but have no idea how popular that one is, or how it compares to alternatives.

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

If there is a way to get this behaviour is a nice way using JUnit, then that might also work.

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

采纳答案by dkatzel

JUnit 4 has parameterized test which is the does the same thing as php data providers

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
    }
}

回答by piotrek

Depending on your needs in flexibility vs readability, you can choose Parameterized- junit's built in option, described by dkatzel. Other options are external junit runners provided by external libraries like zohhak, which let's you do:

根据您在灵活性与可读性方面的需求,您可以选择Parameterized- junit 的内置选项,由 dkatzel 描述。其他选项是外部库提供的外部 junit运行器,例如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)   );
    }

or junitParamswith a bit different functionality. just pick whatever suits you the most

junitParams具有一些不同的功能。只选择最适合你的

回答by Ingo Bürk

Coworkers of mine at our company wrote a freely available DataProvider in TestNG style for JUnit which you can find on github (https://github.com/TNG/junit-dataprovider).

我公司的同事为 JUnit 编写了一个可免费使用的 TestNG 风格的 DataProvider,你可以在 github (https://github.com/TNG/junit-dataprovider) 上找到

We use it in very large projects and it works just fine for us. It has some advantages over JUnit's Parameterizedas it will reduce the overhead of separate classes and you can execute single tests as well.

我们在非常大的项目中使用它,它对我们来说效果很好。它比 JUnit 有一些优势,Parameterized因为它会减少单独类的开销,并且您也可以执行单个测试。

An example looks something like this

一个例子看起来像这样

@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 );
}

Edit:Since v1.7, it also supports other ways to provide data (strings, lists) and can inline the provider so that a separate method is not necessarily needed.

编辑:从 v1.7 开始,它还支持其他方式提供数据(字符串、列表),并且可以内联提供者,因此不一定需要单独的方法。

A full, working example can be found on the manual page on github. It also has a few more features, like collecting the providers in utility classes and accessing them from other classes etc. The manual page is very detailed, I'm sure you'll find any questions answered there.

可以在 github 的手册页上找到完整的工作示例。它还具有更多功能,例如收集实用程序类中的提供者并从其他类访问它们等。手册页非常详细,我相信您会在那里找到任何问题的答案。

回答by ErikE

Here is another option. You don't have to use Google Guava, that is just my implementation.

这是另一种选择。您不必使用 Google Guava,这只是我的实现。

This uses the same @Parametersas @dkatzel's answer, but instead of the class taking the arguments, the @Parametersannotation goes on specific test methods, so you can pick and choose which methods use that set of arguments.

这与@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());
    }
}

回答by JustAC0der

You can use JUnit 5's ParameterizedTest. Here's an example from https://www.petrikainulainen.net/programming/testing/junit-5-tutorial-writing-parameterized-tests/:

您可以使用 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)
        );
    }
}

It's possible to load test parameters from an annotation, a method or even a CSV file.

可以从注释、方法甚至 CSV 文件加载测试参数。