轉自:Mockito 中文文檔 ( 2.0.26 beta )java
轉自:手把手教你 Mockito 的使用git
參數匹配器
Argument Matcher(參數匹配器)github
@Test public void argumentMatchersTest(){ List<String> mock = mock(List.class); when(mock.get(anyInt())).thenReturn("Hello").thenReturn("World"); String result=mock.get(100)+" "+mock.get(200); verify(mock,times(2)).get(anyInt()); assertEquals("Hello World",result); }
@Test public void argumentMatchersTest(){ Map mapMock = mock(Map.class); when(mapMock.put(anyInt(), anyString())).thenReturn("world"); mapMock.put(1, "hello"); verify(mapMock).put(anyInt(), eq("hello")); }
在最後的驗證時若是隻輸入字符串」hello」是會報錯的,必須使用Matchers類內建的eq方法。若是將anyInt()換成1進行驗證也須要用eq(1)。segmentfault
自定義匹配器-ArgumentMatcher抽象類
自定義參數匹配器的時候須要繼承ArgumentMatcher抽象類,它實現了Hamcrest框架的Matcher接口,定義了describeTo方法,因此咱們只須要實現matches方法在其中定義規則便可。
下面自定義的參數匹配器是匹配size大小爲2的List:框架
1 class IsListOfTwoElements extends ArgumentMatcher<List> { 2 @ 3 public boolean matches(Object list) { 4 return ((List) list).size() == 2; 5 } 6 } 7 8 @Test 9 public void argumentMatchersTest(){ 10 List mock = mock(List.class); 11 when(mock.addAll(argThat(new IsListOfTwoElements()))).thenReturn(true); 12 13 mock.addAll(Arrays.asList("one", "two", "three")); 14 verify(mock).addAll(argThat(new IsListOfTwoElements())); 15 }
argThat(Matcher<T> matcher)方法用來應用自定義的規則,能夠傳入任何實現Matcher接口的實現類。上例中在stubbing和verify addAll方法時經過argThat(Matcher<T> matcher),傳入了自定義的參數匹配器IsListOfTwoElements用來匹配size大小爲2的List。由於例子中傳入List的元素爲三個,因此測試將失敗。
較複雜的參數匹配將會下降測試代碼的可讀性。有時實現參數對象的equals()方法是個不錯的選擇(Mockito默認使用equals()方法進行參數匹配),它可使測試代碼更爲整潔。另外,有些場景使用參數捕獲器(ArgumentCaptor)要比自定義參數匹配器更加合適。 異步
如何捕獲 mock 方法的調用參數
Mockito以java代碼風格的形式來驗證參數值 : 即經過使用equals()
函數。這也是咱們推薦用於參數匹配的方式,由於這樣會使得測試代碼更簡單、簡潔。在某些狀況下,當驗證交互以後要檢測真實的參數值時這將變得有用。例如 :函數
1 @Test 2 public void captureNonGenericArgument() { 3 UserDao userDao = Mockito.mock(UserDao.class); 4 UserService userService = new UserService(userDao); 5 6 userService.saveUser(new User(null, "Yanbin")); 7 8 ArgumentCaptor<User> argumentCaptor = ArgumentCaptor.forClass(User.class); 9 verify(userDao, times(1)).save(argumentCaptor.capture()); 10 11 assertEquals("Yanbin", argumentCaptor.getValue().name); 12 assertEquals("Chicago", argumentCator.getValue().city); //可斷言捕獲參數的更多特徵
從面對被捕獲參數 argumentCaptor.getValue()
的斷言可看出它比 argThat()
的優點,argThat() 沒法告訴咱們不匹配的細節工具
警告 : 咱們建議使用沒有測試樁的ArgumentCaptor來驗證,由於使用含有測試樁的ArgumentCaptor會下降測試代碼的可讀性,由於captor是在斷言代碼塊以外建立的。另外一個好處是它能夠下降本地化的缺點,由於若是測試樁函數沒有被調用,那麼參數就不會被捕獲。總之,ArgumentCaptor與自定義的參數匹配器相關(能夠查看ArgumentMatcher類的文檔 )。這兩種技術都能用於檢測外部傳遞到Mock對象的參數。然而,使用ArgumentCaptor在如下的狀況下更合適 :測試
- 自定義不能被重用的參數匹配器
- 你僅須要斷言參數值
咱們一樣能夠在打樁的時候捕獲參數,如ui
1 ArgumentCaptor<User> argumentCaptor = argumentCaptor.forClass(User.class); 2 when(userDao.findUserLike(argumentCaptor.capture)).thenReturn(Mockito.mock(User.class)); 3 4 assertEquals("Yanbin", argumentCaptor.getValue().name);
不能以這種方式在打樁的時候捕獲參數:
1 when(userDao.findUserLike(argumentCaptor.capture)).thenReturn(getUser(argumentCaptor.getValue()));
不然會報錯:
出錯位置在打樁的地方。記住打樁並不等於異步調用,它返回的是個固定值!