JUnit 5中的@TestInstance注释有什么用?

Mah*_*zad 15 java testing junit unit-testing junit5

您能否简单说明@TestInstance一下注释,以及它如何在JUnit 5中有用?

我认为我们可以通过使字段静态化来达到相同的效果。

gly*_*ing 13

我认为文档提供了有用的摘要:

如果您希望JUnit Jupiter在同一个测试实例上执行所有测试方法,只需使用@TestInstance(Lifecycle.PER_CLASS)注释您的测试类。使用此模式时,每个测试类将创建一个新的测试实例。因此,如果您的测试方法依赖于实例变量中存储的状态,则可能需要在@BeforeEach或@AfterEach方法中重置该状态。

与默认的“按方法”模式相比,“按类”模式具有一些其他优点。具体来说,使用“按类”模式可以在非静态方法以及接口默认方法上声明@BeforeAll和@AfterAll。因此,“每类”模式还可以在@Nested测试类中使用@BeforeAll和@AfterAll方法。

但是您可能已经读过了,并且认为将字段静态化与将字段声明为实例变量并使用效果相同@TestInstance(Lifecycle.PER_CLASS)

因此,也许“在JUnit 5中如何有用”这个问题的答案是使用@TestInstance...

  • 明确表明您的意图。可以假定使用static关键字是偶然的,而使用的@TestInstance可能性较小是偶然的,或者是尽管复制n粘贴较少的结果。
  • 委托管理范围和生命周期并清理框架的责任,而不必记住自己进行管理。

  • 如果您想在嵌套测试类中使用 MethodSource 创建参数化测试,这也是一个先决条件 https://github.com/junit-team/junit5/issues/1229 (3认同)

Isu*_*dra 8

由于没有人提供正确的编码示例,我想提供一个简单的代码示例,如下所示来理解这个概念,

每个方法示例 - Junit5 中的默认选项 请注意,两个方法是静态的,否则会引发异常,因为类在每个方法中实例化。

@TestInstance(Lifecycle.PER_METHOD)
public class MathUtilTestPerMethod {

    MathUtil util;

    @BeforeAll
    static void beforeAllInit() {
        System.out.println("running before all");
    }

    @AfterAll
    static void afterAllCleanUp() {
        System.out.println("running after all");
    }

    @BeforeEach
    void init() {
        util = new MathUtil();
        System.out.println("running before each...");
    }

    @AfterEach
    void cleanUp() {
        System.out.println("running after each...");
    }

    @Test
    void testSum() {
        assertEquals(2, util.addtwoNumbers(1, 1));
    }

}
Run Code Online (Sandbox Code Playgroud)

每个类示例 请注意,静态已从两个方法中删除,并且 MathUtil 对象是全局创建的,而不是在方法中创建的,因为类仅实例化一次。

@TestInstance(Lifecycle.PER_CLASS)
public class MathUtilTestPerClass {

    MathUtil util = new MathUtil();

    @BeforeAll
    void beforeAllInit() {
        System.out.println("running before all");
    }

    @AfterAll
    void afterAllCleanUp() {
        System.out.println("running after all");
    }

    @BeforeEach
    void init() {
        System.out.println("running before each...");
    }

    @AfterEach
    void cleanUp() {
        System.out.println("running after each...");
    }

    @Test
    void testSum() {
        assertEquals(2, util.addtwoNumbers(1, 1));
    }

}
Run Code Online (Sandbox Code Playgroud)


小智 6

引入此注释是为了减少运行单元测试时创建的对象数量。

添加@TestInstance(TestInstance.Lifecycle.PER_CLASS)到测试类将避免为该类中的每个测试创建新的类实例。当您在同一个测试类中有很多测试并且此类的实例化非常昂贵时,这特别有用。

该注释应谨慎使用。所有单元测试都应隔离并且彼此独立。如果其中一项测试更改了测试类的状态,则您不应使用此功能。

使字段保持静态以实现相同的效果不是一个好主意。确实可以减少创建的对象的数量,但是当执行测试类中的所有测试时,无法清除它们。当您拥有庞大的测试套件时,这可能会导致问题。

  • 我喜欢这个答案,因为它直接解决了使用静态字段的主要缺点。 (2认同)

cas*_*lin 5

@TestInstance用于为带注释的测试类或测试接口配置测试实例生命周期

  • PER_CLASS:每个测试类将创建一个新的测试实例。
  • PER_METHOD:将为每种测试方法,测试工厂方法或测试模板方法创建一个新的测试实例。此模式类似于JUnit版本1至4中的行为。

如果@TestInstance未在测试类或由测试类实现的测试接口上明确声明,则生命周期模式将隐式默认为PER_METHOD


将测试实例生命周期模式设置为PER_CLASS启用以下功能:

  • 给定测试类中的测试方法之间以及测试类中的非静态方法@BeforeAll@AfterAll方法之间共享的测试实例状态。
  • 测试类中的声明@BeforeAll@AfterAll方法@Nested
  • 宣言@BeforeAll@AfterAll对接口的默认方法。
  • 使用Kotlin编程语言实现的测试类中的简化声明@BeforeAll@AfterAll方法。

有关更多详细信息,请参见测试实例生命周期文档。