我正在编写一个单元测试类(使用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");
}
}
答案 0 :(得分:5)
问题在于TestNG会创建测试类ExampleTest
的一个实例,这是您的@Test
两种方法都使用的实例。
因此,当您使用@BeforeClass
时,如果首先运行testNormalCase()
并更改了测试类的状态,那么testExceptionalCase()
会出现随机失败。
当您将注释更改为@BeforeMethod
时,会导致在执行每个@Test
方法之前执行设置。
因此,设置将修复testNormalCase()
的状态,这就是它将通过的原因,并且由于testExceptionalCase()
在内部使用Mockito.when()
更改状态然后运行断言,它将通过所有时间也是。
但有一种情况,您的设置仍然会失败,即,当您在TestNG套件xml文件中的parallel="methods"
标记中使用<suite>
属性时,即配置TestNG时并指示它并行运行每个@Test
方法。
在这种情况下,Mockito.when()
中的testExceptionalCase()
会影响共享状态[因为您在所有this
方法中]以共享方式使用@Test
导致{ {1}}随机失败。
要解决此问题,我建议您执行以下操作:
testNormalCase()
方法之间共享this
,而是将其单独存放在测试类之外,即将测试类的所有数据成员存放在单独的pojo中嘲笑而不是嘲笑@Test
。this
存储ThreadLocal
模拟的状态,然后在Mockito.when()
方法中的ThreadLocal
上运行断言。