JUnit 测试中的成员变量

use*_*644 4 java junit

我在运行一些单元测试时遇到了一些有趣的事情。我有以下方法:

private void createSchemaIfNecessary() throws SQLException, IOException{
    if(!schemaExists){
         try (Connection connection = dataSource.getConnection(); Statement statement = connection.createStatement();) {
             statement.execute(getSQLByFileName(GOLF_COURSE_TABLE_CREATION_SCRIPT));
             statement.execute(getSQLByFileName(GOLF_COURSE_HOLE_TABLE_CREATION_SCRIPT));
             connection.commit();
             schemaExists = true;
         }
    }
}
Run Code Online (Sandbox Code Playgroud)

每个单元测试都会调用此方法来确定是否创建表。该schemaExists变量是一个成员变量。我注意到,当每个测试运行时,有些情况下,即使在到达终点线后schemaExists = true;,下次调用该方法时,schemaExists也会评估为 false。然后我将变量设置为静态,这解决了问题。

当各个单元测试运行时,它们不是都在单元测试类的单个实例的上下文中运行吗?

Ray*_*Ray 5

我假设schemaExists是您的测试类的非静态成员。

在调用测试方法(带注释@Test)之前,junit(默认情况下)会创建测试类的新实例(更多详细信息请参见此处)。

因此,任何非静态类成员都将按照类中的定义进行初始化。如果未显式初始化,则它们将被设置为其默认值,因此 if schemaExists是 a boolean(primitive) then false

我建议,如果您想为所有测试设置共享的内容,您要做的就是创建一个@BeforeClass静态方法来初始化静态属性。

  • 这将确保在运行任何测试方法之前,它仅针对给定的测试类运行一次
  • 对于阅读您代码的其他人来说,该方法的意图非常清楚

以下是 OP 中的数据库模式初始化代码的示例:

@BeforeClass 
public static void setupDBOnce() {
   Connection connection = dataSource.getConnection(); 
   Statement statement = connection.createStatement();  
   statement.execute(getSQLByFileName(GOLF_COURSE_TABLE_CREATION_SCRIPT));
   statement.execute(getSQLByFileName(GOLF_COURSE_HOLE_TABLE_CREATION_SCRIPT));
   connection.commit();
 }
Run Code Online (Sandbox Code Playgroud)

如果由于某种原因您不希望这种行为(每个测试方法运行一个实例),您可以执行以下任一操作

  • 注释你的类@TestInstance(Lifecycle.PER_CLASS)
  • 传递以下虚拟机参数:-Djunit.jupiter.testinstance.lifecycle.default=per_class
  • junit-platform.properties创建或添加到名为在类路径的源根目录中找到的现有属性文件中的条目:junit.jupiter.testinstance.lifecycle.default = per_class

如果您确实覆盖默认值,请记住文档中的一个注释:

使用此模式时,每个测试类都会创建一个新的测试实例。因此,如果您的测试方法依赖于存储在实例变量中的状态,您可能需要在 @BeforeEach 或 @AfterEach 方法中重置该状态。