Java JUnit5中的@TestInstance注释有什么用途?
您能否简单解释一下Java JUnit5中的@TestInstance注释有什么用途?,java,unit-testing,testing,junit,junit5,Java,Unit Testing,Testing,Junit,Junit5,您能否简单解释一下@TestInstance注释,以及它在JUnit5中的用途 我认为我们可以通过使我们的字段保持静态达到同样的效果,我认为可以提供一个有用的总结: 如果您希望JUnit Jupiter在同一个测试实例上执行所有测试方法,只需使用@TestInstance(Lifecycle.PER_class)注释您的测试类即可。使用此模式时,每个测试类将创建一个新的测试实例。因此,如果测试方法依赖于实例变量中存储的状态,则可能需要在@beforeach或@AfterEach方法中重置该状态
@TestInstance
注释,以及它在JUnit5中的用途
我认为我们可以通过使我们的字段保持静态
达到同样的效果,我认为可以提供一个有用的总结:
如果您希望JUnit Jupiter在同一个测试实例上执行所有测试方法,只需使用@TestInstance(Lifecycle.PER_class)注释您的测试类即可。使用此模式时,每个测试类将创建一个新的测试实例。因此,如果测试方法依赖于实例变量中存储的状态,则可能需要在@beforeach或@AfterEach方法中重置该状态
“每类”模式比默认的“每方法”模式有一些额外的好处。具体来说,使用“每类”模式,可以在非静态方法以及接口默认方法上声明@BeforeAll和@AfterAll。因此,“每类”模式还可以在@嵌套测试类中使用@BeforeAll和@AfterAll方法
但您可能已经读过这篇文章,并且您认为将字段设置为静态与将字段声明为实例变量并使用@TestInstance(Lifecycle.PER_CLASS)
具有相同的效果,这是正确的
因此,“它在JUnit5中如何有用”这个问题的答案可能是使用@TestInstance
- 你的意图是明确的。可以假设使用static关键字是偶然的,而使用
则不太可能是偶然的,或者是不考虑复制粘贴的结果@TestInstance
- 将管理范围和生命周期以及清理框架的责任委派给他人,而不必记住自己管理
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
添加到测试类将避免为类中的每个测试创建新的类实例。
当您在同一个测试类中有很多测试,并且该类的实例化成本很高时,这一点特别有用
应谨慎使用此注释。所有单元测试都应该相互隔离和独立。如果其中一个测试更改了测试类的状态,则不应使用此功能
将字段设置为静态以达到相同的效果不是一个好主意。它确实会减少创建的对象数量,但在执行测试类中的所有测试时,无法清理这些对象。当您有一个庞大的测试套件时,这可能会导致问题。用于为带注释的测试类或测试接口配置测试实例的生命周期:
- :每个测试类将创建一个新的测试实例
- :将为每个测试方法、测试工厂方法或测试模板方法创建新的测试实例。此模式类似于JUnit版本1到4中的行为
将测试实例生命周期模式设置为启用以下功能:
- 给定测试类中的测试方法之间以及测试类中的非静态方法之间的共享测试实例状态
- 在
测试类中声明@嵌套的
和@之前
方法@之后
- 在接口默认方法上声明
和@BeforeAll
@aftereall
- 在用Kotlin编程语言实现的测试类中,简化了
和@BeforeAll
方法的声明@aftereall
有关更多详细信息,请参阅文档。由于没有人提供正确的编码示例,因此我想给出一个简单的代码示例,如下所示,以了解该概念 每个方法示例-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));
}
}
每类样本
请注意,静态从这两个方法中删除,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));
}
}
这在用Kotlin语言编写测试时也很有用,因为它没有静态方法 因此,不要在
@BeforeAll
或@aftereall
中使用带有@JvmStatic
funs的伴生对象,而是将生命周期设为每类,并使用@BeforeAll
或@aftereall
注释常规方法:
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class MyTest {
@BeforeAll
fun setup() {
println("Invoked only once")
}
}
使用此方法时,如果需要,请小心在每个
方法之前或之后重置实例变量
多亏了。我喜欢这个答案,因为它直接解决了使用静态字段的一个主要缺点。如果您想在嵌套测试类中使用MethodSource创建参数化测试,那么这也是一个先决条件。使测试类成员为静态可能会在类层次结构中出现问题。多态性为您提供了一些很酷的选项来编写更干净、冗余更少的代码@TestInstance(每类)
应该是Jupiter IMHO中的默认值。它产生了更好、更具弹性的测试代码,与其他测试代码相比,它只有优势。