單元測試 筆記
標籤(空格分隔): 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().doReturn
和doReturn().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);
}