Mock單元測試
單元測試的思路是在不涉及依賴的情況下測試代碼,一般是測試service層的方法,但實際的代碼常會涉及到依賴,一個可行的方法就是使用模擬對象來替換依賴對象。
1.使用Mockito生成mock對象
Mockito 是一個流行 mock 框架,可以和JUnit結合起來使用。Mockito 允許你創建和配置 mock 對象。使用Mockito可以明顯的簡化對外部依賴的測試類的開發。
一般使用 Mockito 需要執行下面三步
-
模擬並替換測試代碼中外部依賴。
-
執行測試代碼
-
驗證測試代碼是否被正確的執行
1.1.在maven中添加mockito依賴
<dependency> <groupId>org.mockito</groupId> <artifactId>mockito-all</artifactId> <scope>test</scope> </dependency>
1.2.靜態引用
如果在代碼中靜態引用了org.mockito.Mockito.*;
,那你你就可以直接調用靜態方法和靜態變量而不用創建對象,譬如直接調用 mock() 方法。
1.3.使用 Mockito 創建和配置 mock 對象
Mockito 還支持通過 @Mock
註解的方式來創建 mock 對象
使用註解,那麽必須要實例化 mock 對象。Mockito 在遇到使用註解的字段的時候,會調用MockitoAnnotations.initMocks(this)
來初始化該 mock 對象。另外也可以通過使用@RunWith(MockitoJUnitRunner.class)
來達到相同的效果。
註解
- @Mock:創建 mock 對象
- @InjectMocks 在 Mockito 中進行依賴註入
調用方法:
when(…?.).thenReturn(…?.)可以被用來定義當條件滿足時函數的返回值,如果你需要定義多個返回值,可以多次定義。當你多次調用函數的時候,Mockito 會根據你定義的先後順序來返回返回值。Mocks 還可以根據傳入參數的不同來定義不同的返回值。譬如說你的函數可以將anyString 或者 anyInt作為輸入參數,然後定義其特定的放回值。
自定義方法的返回值
Mockito.when(方法).thenReturn(返回值)
Mockito.when(方法).thenReturn(返回值1).thenReturn(返回值2)
無返回值
對於無返回值的函數,我們可以使用doReturn(…?).when(…?).methodCall來獲得類似的效果。例如我們想在調用某些無返回值函數的時候拋出異常,那麽可以使用doThrow 方法。如下面代碼片段所示
Mockito.doThrow(new IOException()).when(mockStream).close()
僅調用方法,但啥也不做
Mockito.doNothing().when(tagRepository).deleteByTagId(1)
驗證 query 方法是否被 MyDatabase 的 mock 對象調用
verify(databaseMock).query("* from t");
查看在傳入參數為12的時候方法是否被調用
verify(test).testing(Matchers.eq(12));
方法是否被調用兩次
verify(test, times(2)).getUniqueId();
verify(mock, never()).someMethod("never called");
verify(mock, atLeastOnce()).someMethod("called at least once");
verify(mock, atLeast(2)).someMethod("called at least twice");
verify(mock, times(5)).someMethod("called five times");
verify(mock, atMost(3)).someMethod("called at most 3 times");
1.4.mockito的限制
下面三種數據類型則不能夠被測試
-
final classes
-
anonymous classes
-
primitive types
Mockito 不能夠 mock 靜態方法,因此我們可以使用 Powermock
2.powerMock
powerMock能mock靜態、final、私有方法等
PowerMock支持EasyMock和Mockito。
2.1PowerMock有兩個重要的註解:
[email protected](PowerMockRunner.class)
[email protected]( { YourClassWithEgStaticMethod.class })
[email protected]t,[email protected](PowerMockRunner.class),反之亦然。當你需要使用PowerMock強大功能(Mock靜態、final、私有方法等)的時候,就需要加註解
@PrepareForTest。
2.2基本用法
詳見 http://blog.csdn.net/knighttools/article/details/44630975
2.2.1和普通Mock的用法相同
PowerMockito.when(file.exists()).thenReturn(true);
2.2.2 Mock方法內部new出來的對象
File file = PowerMockito.mock(File.class);
ClassUnderTest underTest = new ClassUnderTest();
PowerMockito.whenNew(File.class).withArguments("bbb").thenReturn(file);
PowerMockito.when(file.exists()).thenReturn(true);
2.2.3 Mock普通對象的final方法
ClassDependency depencency = PowerMockito.mock(ClassDependency.class);
ClassUnderTest underTest = new ClassUnderTest();
PowerMockito.when(depencency.isAlive()).thenReturn(true);
2.2.4.Mock普通類的靜態方法
PowerMockito.mockStatic(ClassDependency.class);
PowerMockito.when(ClassDependency.isExist()).thenReturn(true);
2.2.5 Mock 私有方法
ClassUnderTest underTest = PowerMockito.mock(ClassUnderTest.class);
PowerMockito.when(underTest.callPrivateMethod()).thenCallRealMethod();
PowerMockito.when(underTest, "isExist").thenReturn(true);
2.2.6. Mock系統類的靜態和final方法
ClassUnderTest underTest = new ClassUnderTest();
PowerMockito.mockStatic(System.class);
PowerMockito.when(System.getProperty("aaa")).thenReturn("bbb");
2.2.7 驗證方法
(1) 驗證靜態方法:
PowerMockito.verifyStatic();
Static.firstStaticMethod(param);
(2) 擴展驗證:
PowerMockito.verifyStatic(Mockito.times(2)); // 被調用2次
Static.thirdStaticMethod(Mockito.anyInt()); // 以任何整數值被調用
Mock單元測試