Mock測試就是在測試過程當中,對於某些不容易構造或者不容易獲取的對象,用一個虛擬的對象來建立以便測試的測試方法。什麼是不容易構造的對象呢?例如HttpServletRequest,須要在有servlet容器環境中建立獲取。那不容易獲取的對象呢?如一個JedisCluster,須要準備redis相關環境,而後設置進去等等。html
Mock 能夠分解在單元測試中耦合的其餘類或者接口,它可以幫你模擬這些依賴,並幫你驗證所調用的依賴的行爲。java
當咱們須要測試OrderService時,按照咱們常規的作法呢,都是要先準備好redis,跟db的環境,而後構造UserService跟CouponService注入進來,此時須要構建完整的依賴樹,其過程是比較繁瑣的,萬一數據庫連不上,依賴找不到,服務掛了... 時間一長可能會打擊咱們對項目進行單測的積極性,因此這時候頗有必要尋求一種優雅的方式來解決。web
鐺鐺鐺~這時候Mockito出現了(java中Mock框架比較多,可是本篇只介紹這個),它會把那些繁瑣的依賴通通轉化爲Mock Object,以下圖,這樣咱們就能夠專一的進行咱們的單測,減小在解決依賴上浪費的時間了。redis
關於Mockito的簡介這裏就不在贅述了,你們有興趣能夠自行去官方文檔查閱,這裏主要帶你們瞭解一些經常使用的Mock方法。數據庫
maven依賴bash
<dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> <version>2.23.4</version> <scope>test</scope> </dependency>
爲了代碼測試的方便,直接在測試類中靜態導入 import static org.mockito.Mockito.*;微信
@Test public void testMockBase(){ //建立ArrayList的Mock對象 List mockList = mock(ArrayList.class); //pass Assert.assertTrue(mockList instanceof ArrayList); //當咱們mockList調用方法去add("張三")的時候會返回true when(mockList.add("張三")).thenReturn(true); //當咱們mockList調用方法size()的時候返回10 when(mockList.size()).thenReturn(10); //pass Assert.assertTrue(mockList.add("張三")); //pass Assert.assertFalse(mockList.add("李四")); //pass Assert.assertEquals(mockList.size(),10); //null System.out.println(mockList.get(0)); }
mock靜態方法會建立一個Mock對象,因爲 Mock對象 並不會真的執行方法中的代碼,因此若是未指定返回值的話會返回默認值(如19行)。第9、十行咱們指定了mockList在執行特定方法後須要返回的值,因此在assertTrue校驗是沒問題的,可是add("李四"),咱們並沒設置,因此是false。app
//使用mock List mockedList = mock(ArrayList.class); mockedList.add("once"); mockedList.add("twice"); mockedList.add("twice"); mockedList.add("three times"); mockedList.add("three times"); mockedList.add("three times"); //這裏默認是判斷該方法調用times(1),同下 verify(mockedList).add("once"); verify(mockedList, times(1)).add("once"); verify(mockedList, times(2)).add("twice"); verify(mockedList, times(3)).add("three times"); //從沒調用,times(0) verify(mockedList, never()).add("never happened"); //最少一次,最少幾回,最多幾回 verify(mockedList, atLeastOnce()).add("three times"); verify(mockedList, atLeast(2)).add("three times"); verify(mockedList, atMost(5)).add("three times");
其實在上述的代碼中,命名是比較直觀的,因此我這邊就直接註釋在代碼中了。框架
//方法執行在100ms之內的時候能夠經過 verify(mock, timeout(100)).someMethod(); //同上 verify(mock, timeout(100).times(1)).someMethod(); //方法2次調用均沒超過100ms verify(mock, timeout(100).times(2)).someMethod(); verify(mock, timeout(100).atLeast(2)).someMethod();
經過超時檢測能夠校驗咱們的方法邏輯會不會有出現問題而致使超時的地方。maven
linkedList.add("element"); // anyInt() 任何整數咱們都返回 element when(linkedList.get(anyInt())).thenReturn("element"); System.out.print(linkedList.get(10));//返回element
@Test(expected = RuntimeException.class) public void doThrow(){ List list = mock(List.class); doThrow(new RuntimeException()).when(list).add(1); list.add(1); }
public class ArticleManagerTest { @Mock private ArticleCalculator calculator; @Mock private ArticleDatabase database; @Mock private UserProvider userProvider; private ArticleManager manager;
要注意的是,經過註解的方式用使用的話,咱們必須在添加初始化mock的代碼,否則即便標註了註解也會是null
MockitoAnnotations.initMocks(testClass);
關於Mockito更多詳細的用法,你們能夠直接參考官方文檔,由於各類「奇技淫巧」確實比較多,後面也更新對java8 lambda的支持,不少功能仍是期待你們去挖掘~
更多詳細用法可直接參考官方文檔:
static.javadoc.io/org.mockito…
相信當你熟練使用Mockito之後,你會愛上寫單測的,也會讓你代碼健壯性有所增強。有些bug能提早發現的話,總比運行的時候被別人半夜叫起來修復舒服是吧?