2017-08-25 61 views
1

我正在編寫一個單元測試類(使用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"); 
    } 
} 

回答

4

這裏的問題是,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