并行测试共享模拟

问题描述:

我正在编写一个单元测试类(使用testng)嘲笑成员变量(使用Mockito)并行运行测试。我最初在@BeforeClass方法中设置了预期的模拟,并且在每个测试案例中,我通过为每个特殊情况创建一个Mockito.when来打破某些情况。并行测试共享模拟

我所看到的(不出所料)是这些测试不是独立的; Mockito.when在一个测试案例中影响其他人。我注意到我可以在每次测试之前设置模拟,并将@BeforeClass更改为@BeforeMethod。我仍然没有想到这些会一直传递下去,因为测试同时仍然在同一个共享模拟对象上运行。但是,所有测试开始始终传递。我的问题是“为什么”?这最终会失败吗?无论我做什么(Thread.sleep等),我都无法重现失败。

正在使用@BeforeMethod足以使这些测试独立吗?如果是这样,谁能解释为什么?

如下代码示例:

public class ExampleTest { 
    @Mock 
    private List<String> list; 

    @BeforeClass // Changing to @BeforeMethod works for some reason 
    public void setup() throws NoSuchComponentException, ADPRuntimeException { 
     MockitoAnnotations.initMocks(this); 
     Mockito.when(list.get(0)).thenReturn("normal"); 
    } 

    @Test 
    public void testNormalCase() throws InterruptedException { 
     assertEquals(list.get(0), "normal"); // Fails with expected [normal] but found [exceptional] 
    } 

    @Test 
    public void testExceptionalCase() throws InterruptedException { 
     Mockito.when(list.get(0)).thenReturn("exceptional"); 
     assertEquals(list.get(0), "exceptional"); 
    } 
} 

这里的问题是,TestNG的创建您的测试类ExampleTest的一个实例,这是使用您的两个@Test方法的实例。

因此,当您使用@BeforeClass时,如果testExceptionalCase()先运行并更改了测试类的状态,那么将会发生随机故障testNormalCase()

当您将注释更改为@BeforeMethod时,会导致在每执行一次@Test方法之前执行设置。

因此设置将固定状态testNormalCase()这就是为什么它会通过,并自testExceptionalCase()在内部使用改变了Mockito.when()状态,然后运行断言,它会通过所有的时间也是如此。

但是有一个场景,其中,您的设置仍将失败,即,当你使用你的<suite>标签parallel="methods"属性您TestNG的套件XML文件中,即当您配置TestNG的,并指示它并行运行的每@Test方法。

在这种情况下,内testExceptionalCase()Mockito.when()将影响共享状态[因为你在你的所有@Test方法之间共享的方式使用this]造成testNormalCase()随机失败。

为了解决这个问题,我建议你做到以下几点:

  • 不要共享您的@Test方法之间this,但分别容纳它的测试类之外即房子里所有的数据成员你的测试课在一个单独的pojo将被嘲笑,而不是嘲笑this
  • 使用ThreadLocal来存储被Mockito.when()嘲笑的状态,然后从@Test方法中对ThreadLocal运行断言。
+0

我明白,'parallel =“测试”'没有做我认为正在做的事情。有道理,并感谢有关解决此问题的建议,当我更改为'parallel =“methods”'! – ChrisV