Java 具有动态测试数量的 JUnit 测试

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/358802/
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-11 13:49:29  来源:igfitidea点击:

JUnit test with dynamic number of tests

javaunit-testingjunitparameterized-unit-test

提问by Hans-Peter St?rr

In our project I have several JUnittests that e.g. take every file from a directory and run a test on it. If I implement a testEveryFileInDirectorymethod in the TestCasethis shows up as only one test that may fail or succeed. But I am interested in the results on each individual file. How can I write a TestCase/ TestSuitesuch that each file shows up as a separate test e.g. in the graphical TestRunner of Eclipse? (Coding an explicit test method for each file is not an option.)

在我们的项目中,我有几个JUnit测试,例如从目录中获取每个文件并对其运行测试。如果我实现了一个testEveryFileInDirectory方法,TestCase这将显示为只有一个可能失败或成功的测试。但我对每个单独文件的结果感兴趣。如何编写TestCase/TestSuite以便每个文件显示为单独的测试,例如在 Eclipse 的图形化 TestRunner 中?(为每个文件编写显式测试方法不是一种选择。)

Compare also the question ParameterizedTest with a name in Eclipse Testrunner.

还将问题ParameterizedTest 与 Eclipse Testrunner 中的名称进行比较

采纳答案by bruno conde

Take a look at Parameterized Testsin JUnit 4.

查看JUnit 4中的参数化测试

Actually I did this a few days ago. I'll try to explain ...

实际上,我几天前就这样做了。我会尽力解释...

First build your test class normally, as you where just testing with one input file. Decorate your class with:

首先正常构建您的测试类,就像您只使用一个输入文件进行测试一样。装饰你的班级:

@RunWith(Parameterized.class)

Build one constructor that takes the input that will change in every test call (in this case it may be the file itself)

构建一个构造函数,它接受将在每次测试调用中更改的输入(在这种情况下,它可能是文件本身)

Then, build a static method that will return a Collectionof arrays. Each array in the collection will contain the input arguments for your class constructor e.g. the file. Decorate this method with:

然后,构建一个将返回Collection数组的静态方法。集合中的每个数组都将包含类构造函数的输入参数,例如文件。使用以下方法装饰此方法:

@Parameters

Here's a sample class.

这是一个示例类。

@RunWith(Parameterized.class)
public class ParameterizedTest {

    private File file;

    public ParameterizedTest(File file) {
        this.file = file;
    }

    @Test
    public void test1() throws Exception {  }

    @Test
    public void test2() throws Exception {  }

    @Parameters
    public static Collection<Object[]> data() {
        // load the files as you want
        Object[] fileArg1 = new Object[] { new File("path1") };
        Object[] fileArg2 = new Object[] { new File("path2") };

        Collection<Object[]> data = new ArrayList<Object[]>();
        data.add(fileArg1);
        data.add(fileArg2);
        return data;
    }
}

Also check this example

也检查这个例子

回答by Michael Borgwardt

Should be possible in JUnit 3 by inheriting from TestSuiteand overriding the tests()method to list the files and for each return an instance of a subclass of TestCasethat takes the filename as constructor parameter and has a test method that tests the file given in the constructor.

在 JUnit 3 中应该可以通过继承TestSuite和覆盖tests()列出文件的方法,并为每个返回一个子类的实例,该子类TestCase将文件名作为构造函数参数,并具有测试构造函数中给出的文件的测试方法。

In JUnit 4 it might be even easier.

在 JUnit 4 中,它可能更容易。

回答by McDowell

JUnit 3

JUnit 3

public class XTest extends TestCase {

    public File file;

    public XTest(File file) {
        super(file.toString());
        this.file = file;
    }

    public void testX() {
        fail("Failed: " + file);
    }

}

public class XTestSuite extends TestSuite {

    public static Test suite() {
        TestSuite suite = new TestSuite("XTestSuite");
        File[] files = new File(".").listFiles();
        for (File file : files) {
            suite.addTest(new XTest(file));
        }
        return suite;
    }

}

JUnit 4

JUnit 4

import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;

@RunWith(Parameterized.class)
public class TestY {

    @Parameters
    public static Collection<Object[]> getFiles() {
        Collection<Object[]> params = new ArrayList<Object[]>();
        for (File f : new File(".").listFiles()) {
            Object[] arr = new Object[] { f };
            params.add(arr);
        }
        return params;
    }

    private File file;

    public TestY(File file) {
        this.file = file;
    }

    @Test
    public void testY() {
        fail(file.toString());
    }

}

回答by Ben Hutchison

If TestNG is an option, you could use Parameters with DataProviders.

如果 TestNG 是一个选项,您可以将Parameters 与 DataProviders 一起使用。

Each individual file's test will have its result shown in the text-based report or Eclipse's TestNG plugin UI. The number of total tests run will count each of your files individually.

每个单独文件的测试结果都将显示在基于文本的报告或 Eclipse 的 TestNG 插件 UI 中。运行的总测试数将单独计算您的每个文件。

This behavior differs from JUnit Theories, in which all results are lumped under one "theory" entry and only count as 1 test. If you want separate result reporting in JUnit, you can try Parameterized Tests.

这种行为与 JUnit Theories不同,在JUnit Theories中,所有结果都集中在一个“理论”条目下,并且只计为 1 个测试。如果您想在 JUnit 中单独报告结果,您可以尝试Parameterized Tests

Test and inputs

测试和输入

public class FileTest {

    @DataProvider(name="files")
    public File[][] getFiles(){
        return new File[][] {
            { new File("file1") },
            { new File("file2") }
        };
        // or scan a directory
    }

    @Test(dataProvider="files")
    public void testFile(File file){
        //run tests on file
    }
}

Example output

示例输出

PASSED: testFile(file1)
PASSED: testFile(file2)

===============================================
    Default test
    Tests run: 2, Failures: 0, Skips: 0
===============================================

回答by falsarella

You could consider using JUnitParams library, so you would have a few more (cleaner) options:

您可以考虑使用JUnitParams library,因此您将有更多(更干净)的选择:

@org.junit.runner.RunWith(junitparams.JUnitParamsRunner.class)
public class ParameterizedTest {

    @org.junit.Test
    @junitparams.Parameters(method = "data")
    public void test1(File file) throws Exception {  }

    @org.junit.Test
    @junitparams.Parameters(method = "data")
    public void test2(File file) throws Exception {  }

    public static File[] data() {
        return new File[] { new File("path1"), new File("path2") };
    }
}


@org.junit.runner.RunWith(junitparams.JUnitParamsRunner.class)
public class ParameterizedTest {

    @org.junit.Test
    @junitparams.Parameters(value = { "path1", "path2" })
    public void test1(String path) throws Exception {
        File file = new File(path);
    }

    @org.junit.Test
    @junitparams.Parameters(value = { "path1", "path2" })
    public void test2(String path) throws Exception {
        File file = new File(path);
    }
}


You can see more samples of usage here.

您可以在此处查看更多使用示例

In addition about JUnitParams, why writting parameterized tests with it is easier and more readable:

另外关于 JUnitParams,为什么用它编写参数化测试更容易和更易读

JUnitParams project adds a new runner to JUnit and provides much easier and readable parametrised tests for JUnit >=4.6.

Main differences to standard JUnit Parametrised runner:

  • more explicit - params are in test method params, not class fields
  • less code - you don't need a constructor to set up parameters
  • you can mix parametrised with non-parametrised methods in one class
  • params can be passed as a CSV string or from a parameters provider class
  • parameters provider class can have as many parameters providing methods as you want, so that you can group different cases
  • you can have a test method that provides parameters (no external classes or statics anymore)
  • you can see actual parameter values in your IDE (in JUnit's Parametrised it's only consecutive numbers of parameters)

JUnitParams 项目为 JUnit 添加了一个新的运行器,并为 JUnit >=4.6 提供了更简单易读的参数化测试。

与标准 JUnit 参数化运行器的主要区别:

  • 更明确 - 参数在测试方法参数中,而不是类字段
  • 更少的代码 - 您不需要构造函数来设置参数
  • 你可以在一个类中混合参数化和非参数化方法
  • params 可以作为 CSV 字符串或从参数提供程序类传递
  • 参数提供者类可以有任意多的参数提供方法,这样你就可以对不同的情况进行分组
  • 你可以有一个提供参数的测试方法(不再有外部类或静态)
  • 您可以在 IDE 中看到实际的参数值(在 JUnit 的参数化中,它只是连续的参数数量)

回答by Kimble

I had a similar problem and ended up writing a simple JUnit 4 runner that allows med to dynamically generate tests.

我遇到了类似的问题,最终编写了一个简单的 JUnit 4 运行程序,它允许 med 动态生成测试。

https://github.com/kimble/junit-test-factory

https://github.com/kimble/junit-test-factory

回答by avandeursen

Junit 5 Parameterized Tests

Junit 5 参数化测试

JUnit 5parameterized tests support this by allowing the use of a method as data source:

JUnit 5参数化测试通过允许使用方法作为数据源来支持这一点:

@ParameterizedTest
@MethodSource("fileProvider")
void testFile(File f) {
    // Your test comes here
}

static Stream<File> fileProvider() {
    return Arrays.asList(new File(".").list()).stream();
}

JUnit 5 DynamicTests

JUnit 5 动态测试

JUnit 5also supports this through the notion of a DynamicTest, which is to be generated in a @TestFactory, by means of the static method dynamicTest.

JUnit 5还通过 a 的概念支持这一点,aDynamicTest@TestFactory通过静态方法在 a 中生成dynamicTest

import org.junit.jupiter.api.DynamicTest;
import org.junit.jupiter.api.TestFactory;
import static org.junit.jupiter.api.DynamicTest.dynamicTest;

import java.util.stream.Stream;

@TestFactory
public Stream<DynamicTest> testFiles() {
    return Arrays.asList(new File(".").list())
            .stream()
            .map((file) -> dynamicTest(
                    "Test for file: " + file,
                    () -> { /* Your test comes here */ }));
}

The tests run in your IDE (IntelliJ here) will be displayed like this:

在您的 IDE(此处为 IntelliJ)中运行的测试将显示如下:

Output in IntelliJ

IntelliJ 中的输出