使用 JUnit 5 的 @ParametrizedTest 与 @TestFactory Stream<DynamicTest> 之间有什么区别/优势?

What's the difference between / advantage of using JUnit 5's @ParametrizedTest over @TestFactory Stream<DynamicTest>?

首先,Guide to Dynamic Tests in Junit 5结论中的这个是什么意思?

The parameterized tests can replace many of the examples in this article. However, the dynamic tests differ from the parameterized tests as they support full test lifecycle, while parametrized tests don’t.

我浏览了 JUnit 5 – Parameterized Tests 并相信我理解句法层面的差异,并且相信我明白了:

Moreover, dynamic tests provide more flexibility regarding how the input is generated and how the tests are executed.

但似乎,为什么有人更喜欢参数化测试而不是动态测试?

动态测试,我将它们称为小测试,只是 soft/grouped-assertions (assertAll(...)) 类固醇。您会在报告中看到每个生成的动态测试的条目,但它们不是 真实 测试。

您复制到问题中的引用(来自 baeldung)是错误的。它应该像 JUnit 的用户指南中那样阅读:

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.

有关详细信息,请阅读:https://junit.org/junit5/docs/current/user-guide/#writing-tests-dynamic-tests

Why would anyone prefer parametrized tests over dynamic tests?

  1. 如果您需要为每个测试提供完整的生命周期支持(模板调用)。
  2. 如果你想在注释中声明你的参数。

在此处找到有关如何以各种形式向 @ParameterizedTest 提供参数的更多详细信息:https://junit.org/junit5/docs/current/user-guide/#writing-tests-parameterized-tests -- mind that "class/container templates" are slated for a later release: https://github.com/junit-team/junit5/issues/878

我写了一篇博客 post 在这里比较了使用 JUnit Jupiter 分散 3 个断言的 5 个步骤:https://sormuras.github.io/blog/2018-05-14-junit5-scatter-assertions.html

更大的灵活性在某种程度上意味着编写起来更复杂和样板化,尤其是在大多数情况下,测试用例相当静态但不那么动态。

考虑我要测试 Math.add() :

参数化测试版本如下:

@ParameterizedTest
@CsvSource({ "1,1,2",
            "2,2,4",
            "3,3,6",
            "4,4,8",
            "5,5,10",
            "6,6,12",
            "7,7,14",
            "10,90,100" })
public void parameterizedTest(int left, int right, int expected) {
    assertEquals(expected, Math.addExact(left, right));
}

动态测试版如下:

@TestFactory
Collection<DynamicTest> dynamicTest() {
    return Arrays.asList(
      DynamicTest.dynamicTest("Test1", () -> assertEquals(2, Math.addExact(1, 1))),
      DynamicTest.dynamicTest("Test2", () -> assertEquals(4, Math.addExact(2, 2))),
      DynamicTest.dynamicTest("Test3", () -> assertEquals(6, Math.addExact(3, 3))),
      DynamicTest.dynamicTest("Test4", () -> assertEquals(8, Math.addExact(4, 4))),
      DynamicTest.dynamicTest("Test5", () -> assertEquals(10, Math.addExact(5, 5))),
      DynamicTest.dynamicTest("Test6", () -> assertEquals(12, Math.addExact(6, 6))),
      DynamicTest.dynamicTest("Test7", () -> assertEquals(14, Math.addExact(7, 7))),
      DynamicTest.dynamicTest("Test8", () -> assertEquals(100, Math.addExact(10, 90))));
}

它已经有很多样板代码 codes.So 我尝试使用 return Stream<DynamicTest> 来删除这些样板代码:

@TestFactory
Stream<DynamicTest> dynamicTest2() {

    return Stream.of(
                "1,1,2", 
                "2,2,4", 
                "3,3,6",
                "4,4,8" ,
                "5,5,10" , 
                "6,6,12" ,
                "7,7,14", 
                "10,90,100")
                //How to do????????
            .map(data-> DynamicTest.dynamicTest(data, () -> assertEquals(xxx, Math.addExact(yy,zz))));
}

但是如何将字符串格式的测试数据转换为参数并调用 SUT。我环顾四周 DynamicTest API 看看有没有什么可以帮助我但找不到任何有用的东西,所以我放弃了.....

所以,我更喜欢参数化测试。更优雅、干净、易读易写。测试用例的可读性更重要。