从 Java 中的循环创建多个单元测试

Creating multiple unit tests from a loop in Java

我正在为我的(小)程序编写单元测试,测试用例在大约 30 个不同的文件中指定。
为了测试它,我只需要一个遍历所有文件、解析它们并执行所需内容的循环。

问题是,在那种情况下,我的所有测试都将被视为一个测试,因为它们都在同一个函数中,使用 @Test 表示法。
是否可以以某种方式拆分它,而不必为每个测试文件提供单独的功能?

将所有测试作为一个测试用例的问题是,我看不到哪个测试用例失败了;如果一个失败,其余的失败(我会得到 1 个测试失败而不是 5/30 失败)

我目前正在使用 JUnit (4.12),但我没有义务继续使用它,所以如果有更好的解决方案,我可以切换框架。

谢谢!

示例:

public class MyTests {
    @Test
    public void testFromFiles {
        // loop through all the files
    }
}

output: 1 test run successfully 

更新: 所选答案对我来说非常有用,我添加了另一个 JUnit 5 解决方案(而不是 4),以防它对某人有所帮助。

试试这个方法:

@RunWith(Parameterized.class)
public class EdiTest {

    @SuppressWarnings("WeakerAccess")
    @Parameterized.Parameter(value = 0)
    public String model;

    @SuppressWarnings("WeakerAccess")
    @Parameterized.Parameter(value = 1)
    public String filename;

    @Parameterized.Parameters(name = "{index}: testEDI({0}, {1})")
    public static Collection<Object[]> data() {
        return Arrays.asList(new Object[][]{
                {"753", "edi753_A.edi"},
                {"753", "edi753_B.edi"},
                {"754", "edi754.edi"},
                {"810", "edi810-withTax.edi"},
                {"810", "edi810-withoutTax.edi"},
        });
    }

    @Before
    public void setUpContext() throws Exception {
        TestContextManager testContextManager = new TestContextManager(getClass());
        testContextManager.prepareTestInstance(this);
    }

    @Test
    public void testEDI() throws IOException {
        String edi = IOUtils.toString(ClassLoader.getSystemResource(filename));
        EdiConverter driver = ediConverterProvider.getConverter(model);

        // your test code here
    }

}

使用 JUnit 5 和 Dynamic Tests:

  • Basic example:

    class DynamicTests {
    
      @TestFactory
      List<DynamicTest> createSomeTests() {
    
        return Arrays.asList(
          DynamicTest.dynamicTest("First dynamically created test",
            () -> assertTrue(true)),
    
          DynamicTest.dynamicTest("Second dynamically created test",
            () -> assertTrue(true))
        );
      }
    }
    
  • 获取和过滤所有测试文件的示例:

    class MyTestsClass {
        @TestFactory
        List<DynamicTest> runAllTestFiles() {
            List<DynamicTest> list = new ArrayList<DynamicTest>();
            try (Stream<Path> paths = Files.walk(Paths.get("tests_dir"))) {
                List<Path> files = paths
                        .filter(path -> path.getFileName().toString().endsWith(".mytests"))
                        .collect(Collectors.toList());
                files.forEach(file -> list.add(
                        DynamicTest.dynamicTest(
                            file.getFileName().toString(), 
                            () -> testFileWithSomeAsserts(file))
                ));
            } catch (IOException e) {
                e.printStackTrace();
            }
    
            return list;
        }
    }
    

@TestFactory 的工作方式与常规测试不同,在这种情况下无法使用 @BeforeEach / @AfterEach

Dynamic Test Lifecycle

The execution lifecycle of a dynamic test is quite different than it is for a standard @Test case. Specifically, there are no lifecycle callbacks for individual dynamic tests. This means that @BeforeEach and @AfterEach methods and their corresponding extension callbacks are executed for the @TestFactory method but not for each dynamic test. In other words, if you access fields from the test instance within a lambda expression for a dynamic test, those fields will not be reset by callback methods or extensions between the execution of individual dynamic tests generated by the same @TestFactory method.

More examples in the official documentation.