單元測試 筆記

單元測試 筆記

標籤(空格分隔): TestNg mockito


學習鏈接
Mockito官方文檔
極客學院
TestNg
Mockito中文教程

Mockito 使用情景

我們往往會遇到要測試的類有很多依賴,這些依賴的類/對象/資源又有別的依賴,從而形成一個大的依賴樹,要在單元測試的環境中完整地構建這樣的依賴,是一件很困難的事情。

基本使用

    @Test
    public void test() {
        ObjectB objectB = mock(ObjectB.class);
        ObjectA objectA = new ObjectA();
        objectA.setPwString("testString");
        when(objectB.getObjectA()).thenReturn(objectA);

        ObjectA actucalA = objectB.getObjectA();
        assertEquals(objectA, actucalA);
    }

注意使用註釋快速Mock的時候需要MockitoAnnotations.initMocks(this);參考2.5

參數匹配

在匹配方法的參數時候可以寫準確值也可以使用any()

    when(templateDAO.findAll(any(TemplateSpecification.class))).thenThrow(new 
        DataAccessException("query template failed") {
            private static final long serialVersionUID = -6784264998739312988L;
    });
    when(templateDAO.findAll(any(TemplateSpecification.class))).thenThrow(new
        DataAccessException("query template failed") {
    }); 
  • 這裏需要注意的是一旦參數使用了一個matcher,那麼後面的參數都必須matcher
  • 可以自己自定義參數匹配

doReturn().when()和when().doReturn()區別

這裏需要注意一下when().doReturndoReturn().when()的區別

  • doReturn().when()不會真的去調用該方法
  • when().doReturn()在監測對象是完全mock對象的時候不會調用方法(因爲mock就是一個假對象),而當對象是spy的時候會真的去調用該方法
  • 當調用方法返回值是空的時候,只能用doReturn().when().method()

驗證異常

代碼驗證

    @Rule
    public ExpectedException expectedEx = ExpectedException.none(); 
    //...
    expectedEx.expect(CannotUploadTemplateException.class);
    expectedEx.expectMessage("Template Rejected"); 
    expectedEx.expect(CannotUploadTemplateException.class);
    expectedEx.expectMessage("Template Rejected"); 

使用註釋來驗證異常

    @Test(expected = RuntimeException.class)
    public void doThrow_when(){
        List list = mock(List.class);
        doThrow(new RuntimeException()).when(list).add(1);
        list.add(1);
    }

Spy檢測對象

spy是一個可以檢測實際對象的技術,能夠監測方法並設置對象行爲,這裏就需要注意之前所說的doReturn().when()when().doReturn()的區別,理解起來就是一種可實可虛的半mock對象

    @Test
    public void test() {
        ObjectB objectB = spy(new ObjectB());
        ObjectA objectA = new ObjectA();
        objectA.setPwString("testString");
        when(objectB.getObjectA()).thenReturn(objectA);

        ObjectA actucalA = objectB.getObjectA();
        assertEquals(objectA, actucalA);
        //這裏getValue()會調用實際的方法,返回值是"hello world"
        assertEquals("hello world", objectB.getValue());
    }

重置Mock

     @Test
    public void reset_mock(){
        List list = mock(List.class);
        when(list.size()).thenReturn(10);
        list.add(1);
        assertEquals(10,list.size());
        //重置mock,清除所有的互動和預設
        reset(list);
        assertEquals(0,list.size());
    }

連續調用

    @Test(expected = RuntimeException.class)
    public void consecutive_calls(){
        //模擬連續調用返回期望值,如果分開,則只有最後一個有效
        when(mockList.get(0)).thenReturn(0);
        when(mockList.get(0)).thenReturn(1);
        when(mockList.get(0)).thenReturn(2);
        when(mockList.get(1)).thenReturn(0).thenReturn(1).thenThrow(new RuntimeException());
        assertEquals(2,mockList.get(0));
        assertEquals(2,mockList.get(0));
        assertEquals(0,mockList.get(1));
        assertEquals(1,mockList.get(1));
        //第三次或更多調用都會拋出異常
        mockList.get(1);
    }

驗證執行順序

詳情參考2.16

確保模擬對象上無互動發生

詳情參考2.17

找出冗餘的互動(即未被驗證到的)

詳情參考2.18

發佈了65 篇原創文章 · 獲贊 14 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章