22

当我运行以下代码时,两个测试用例都实现了:

import static junit.framework.Assert.assertEquals;

import org.junit.Test;

public class MyTest{
    private int count;

    @Before
    public void before(){
        count=1;
    }

    @Test
    public void test1(){
        count++;
        assertEquals(2, count); 
    }

    @Test
    public void test2(){
        count++;
        assertEquals(2, count); 
    }
}

预期行为

  1. 测试1 - 成功
  2. test2 - 失败(正如预期的那样,计数将变为 3)

实际行为

  1. 测试1 - 成功
  2. 测试2 - 成功

为什么 junitreinitializing class/variable与每个测试方法调用一起使用。这是 junit 中的错误或故意提供的。

4

6 回答 6

22

这是因为测试隔离。

没有测试应该依赖于另一个。

于 2013-10-15T12:38:35.820 回答
19

MyTest每个测试方法的新实例

对于每个测试方法,都会创建一个新实例,这是 Junit 的行为。MyTest

因此,在您的情况下,对于这两种方法,变量count都将具有 value 1,因此两种测试方法的值count++都会通过2,因此测试用例通过。

public class MyTest{
   public MyTest(){
      // called n times
      System.out.println("Constructor called for MyTest");
   }

   @Before //called n times
   public void setUp(){
      System.out.println("Before called for MyTest");
   }
    
   //n test methods
}

如果您使用 2 种测试方法执行上面的代码:

输出将是:

Constructor called for MyTest
Before called for MyTest
//test execution
Constructor called for MyTest
Before called for MyTest

编辑:

隔离测试的FIRST原则

测试框架可以帮助您做正确的事情,单元测试的一个非常重要的属性是隔离

通过为每个测试方法创建一个新实例,脏 SUT 被丢弃。这样我们每次测试都有一个新鲜的状态。

阅读 FIRST 测试原则。

于 2013-10-15T12:43:48.590 回答
8

查看以下文档org.junit.runner.Runner

默认运行程序实现保证测试用例类的实例将在运行测试之前立即构建,并且运行程序不会保留对测试用例实例的引用,通常使它们可用于垃圾收集。

单元测试应该是独立的,否则它变得不可维护。请注意,不保证执行方法的顺序(除非您使用注解@FixMethodOrder)。

于 2013-10-15T12:46:52.997 回答
3

JUnit 5 的答案

在 JUnit5 中,这种行为是使用@TestInstance注解控制的。注释可以取两个生命周期限定符之一作为值:

  • @TestInstance(Lifecycle.PER_CLASS):测试类将为类中的所有方法初始化一次。
  • @TestInstance(Lifecycle.PER_METHOD):测试类将在每个测试方法之前重新初始化(其他答案中描述的行为)。

如果测试类没有用 注释@TestInstance,则默认行为是PER_METHOD

有关更多详细信息,请参阅JUnit5 用户指南中的测试实例生命周期

于 2020-12-19T15:21:37.520 回答
3

如果要对所有测试使用测试类的成员变量,而不将其重新初始化为 null,则将其设为静态

于 2017-12-08T14:04:59.327 回答
1

不要在构造函数中初始化测试类状态,除非它是不可变的。

JUnit 不会为每个@Test. 事实上,它只运行@Before在每个方法之前标记的方法,并且会@BeforeClass在类中的所有测试之前运行一次方法。

但是,您不能保证测试运行程序实际上只会使用您的测试类的一个实例来运行测试。它可以免费使用很多——考虑并行运行一堆测试,甚至在不同的机器上。

虽然通常有 JUnit 运行器设置来控制这一点,但最好简单地遵循 JUnit 设计并在@Before仅标记的方法中初始化测试状态。

于 2013-10-15T12:39:43.030 回答