在我们的项目中,我有几个JUnit测试,例如从目录中获取每个文件并对其进行测试。如果我在中实现了一种testEveryFileInDirectory
方法,则TestCase
显示为仅一个可能失败或成功的测试。但是我对每个文件的结果都很感兴趣。如何编写一个TestCase
/ TestSuite
,使每个文件显示为单独的测试,例如在Eclipse的图形TestRunner中?(为每个文件编写显式测试方法不是一种选择。)
在我们的项目中,我有几个JUnit测试,例如从目录中获取每个文件并对其进行测试。如果我在中实现了一种testEveryFileInDirectory
方法,则TestCase
显示为仅一个可能失败或成功的测试。但是我对每个文件的结果都很感兴趣。如何编写一个TestCase
/ TestSuite
,使每个文件显示为单独的测试,例如在Eclipse的图形TestRunner中?(为每个文件编写显式测试方法不是一种选择。)
Answers:
看看JUnit 4 中的参数化测试。
实际上,我几天前就这样做了。我会尽力解释...
首先,正常构建测试类,就像在一个输入文件中进行测试一样。用以下方式装饰您的课程:
@RunWith(Parameterized.class)
构建一个构造函数,该构造函数接受在每次测试调用中都会更改的输入(在这种情况下,它可能是文件本身)
然后,构建一个静态方法,该方法将返回一个Collection
数组。集合中的每个数组都将包含类构造函数的输入参数,例如文件。用以下方法装饰此方法:
@Parameters
这是一个示例类。
@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;
}
}
还要检查这个例子
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
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());
}
}
Junit 5参数化测试
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动态测试
JUnit 5还通过a的概念来支持这一点,该概念DynamicTest
将@TestFactory
通过static方法在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 */ }));
}
在IDE(此处为IntelliJ)中运行的测试将显示如下:
您可以考虑使用JUnitParams库,因此您将有更多(更简洁)的选择:
@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);
}
}
除了关于JUnitParams之外,为什么用它编写参数化测试也更容易和更容易理解:
JUnitParams项目为JUnit添加了新的运行器,并为JUnit> = 4.6提供了更简单易读的参数化测试。
与标准JUnit参数化运行器的主要区别:
- 更明确-参数在测试方法参数中,而不是类字段中
- 更少的代码-您不需要构造函数来设置参数
- 您可以在一类中将参数化方法与非参数化方法混合使用
- 参数可以作为CSV字符串或从参数提供程序类传递
- 参数提供程序类可以具有任意数量的参数提供方法,以便可以将不同的情况分组
- 您可以使用提供参数的测试方法(不再使用外部类或静态变量)
- 您可以在IDE中看到实际的参数值(在JUnit的Parametricsed中,它只是连续的参数数量)
如果可以选择TestNG,则可以将Parameters与DataProviders一起使用。
每个文件的测试结果都将显示在基于文本的报告或Eclipse的TestNG插件UI中。运行的总测试次数将分别计算每个文件。
此行为不同于JUnit 理论,在JUnit 理论中,所有结果都集中在一个“ theory”条目下,并且仅计为1个测试。如果要在JUnit中单独报告结果,可以尝试Parameterized Tests。
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
}
}
PASSED: testFile(file1)
PASSED: testFile(file2)
===============================================
Default test
Tests run: 2, Failures: 0, Skips: 0
===============================================
我遇到了类似的问题,最终编写了一个简单的JUnit 4运行程序,该程序允许med动态生成测试。