前言
上一篇的《Mockito-入门》主要是让大家对Mockito有个初步的认识,本篇则是对官方文档对Mockito的介绍进行解释。大家也可以去http://mockito.googlecode.com/svn/branches/1.6/javadoc/org/mockito/Mockito.html进行查看。
正题
Mockito的主要用途就是用来模拟对象(Mock)、验证方法被调用次数(Verification)、返回期望值(Stubbing)。
1.Let‘s verify some behaviour!-验证行为
Once created, mock will remember all interactions.——来自官网
即一旦一个mock对象被创建,那么该对象所有交互行为都会被记住。比如下面例子中它可以记住mockedList某个方法是否被调用过或者被调用过几次。
import static org.mockito.Mockito.*; import java.util.List; import org.junit.Test; public class TestMockito { @Test public void testMockito1(){ // 创建模拟对象 List mockedList = mock(List.class); //using mock object mockedList.add("one"); mockedList.clear(); // 验证add方法是否在前面被调用了一次,且参数为“one”。clear方法同样。 verify(mockedList).add("one"); verify(mockedList).clear(); // 下面的验证会失败。因为没有调用过add("two")。 verify(mockedList).add("two"); } }
2.How about some stubbing? -返回期望值
By default, for all methods that return value, mock returns null, an empty collection or appropriate primitive/primitive wrapper value (e.g: 0, false, ... for int/Integer,
boolean/Boolean, ...).——来自官网
对于有返回值但没有设置期望值的模拟对象,Mockito会返回相应的默认值,内置类型int会返回0,boolean返回false,其他则返回null。
这个返回默认值主要是因为Mock对象会覆盖(override)整个被Mock的对象的方法,所以没有设置期望值的就只能返回默认值了。
@Test public void testMockito2() { // 我们不仅可以模拟接口还可以模拟具体类。 LinkedList mockedList = mock(LinkedList.class); // stubbing 当get(0)被调用时,返回"first". 方法get(1)被调用时,抛异常 when(mockedList.get(0)).thenReturn("first"); when(mockedList.get(1)).thenThrow(new RuntimeException()); // 下面会输出"first" System.out.println(mockedList.get(0)); // 下面会输出"null",因为999没有被设置期望值 System.out.println(mockedList.get(999)); // 下面会抛出异常,因为设置的返回值是异常(想要testMokito2测试通过,将下面这一行get(1)注释即可) System.out.println(mockedList.get(1)); //重复stub两次,则以第二次为准。如下将返回"second": when(mockedList.get(0)).thenReturn("first"); when(mockedList.get(0)).thenReturn("second"); // 输出"second" System.out.println(mockedList.get(0)); //如果是下面这种形式,则表示第一次调用时返回“first”,第二次调用时返回“second”。可以写n多个。 when(mockedList.get(0)).thenReturn("first").thenReturn("second"); // 输出"first" System.out.println(mockedList.get(0)); // 输出"second" System.out.println(mockedList.get(0)); // 输出"second" System.out.println(mockedList.get(0)); }
3.Argument matchers-参数匹配
If you are using argument matchers, all arguments have to be provided by matchers.——来自官网
有关参数匹配很重要的一点:一旦某个方法的参数使用了参数匹配,则该方法所有的参数都得使用参数匹配。
@Test public void testMockito3() { LinkedList mockedList = mock(LinkedList.class); // 使用內置的參數匹配函數anyInt() when(mockedList.get(anyInt())).thenReturn("element"); // 也可以使用自定義的匹配類,比如下面的isValid就是一個自定義的匹配器 when(mockedList.contains(argThat(isValid()))).thenReturn(false); // 下面會輸出"element" System.out.println(mockedList.get(999)); // 也可以通過參數匹配方法進行驗證 verify(mockedList).get(anyInt()); // 下面的方法會報錯,因為第一個參數沒有使用參數匹配,而第二個參數使用了參數匹配 verify(mockedList).set(1, anyString()); } private Matcher<String> isValid(){ return Matchers.any(); }
4.Verifying exact number of invocations / at least x / never-验证调用的具体次数/最少次数/从未调用
times(1) is the default. Therefore using times(1) explicitly can be omitted.——来自官网
默认调用一次,所以对于1次我们可以省略掉times(1).
@Test public void testMockito4() { LinkedList mockedList = mock(LinkedList.class); // using mock mockedList.add("once"); mockedList.add("twice"); mockedList.add("twice"); mockedList.add("three times"); mockedList.add("three times"); mockedList.add("three times"); // 下面兩種寫法都是針對調用1次,因為1是默認的,我們一般使用第一種寫法就可以 verify(mockedList).add("once"); verify(mockedList, times(1)).add("once"); // 指定了具體調用的次數 verify(mockedList, times(2)).add("twice"); verify(mockedList, times(3)).add("three times"); // 使用了never(),即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"); }
5.Stubbing void methods with exceptions-设置void方法的返回值为抛异常
Mockito起初有一个stubVoid(Object)方法专门针对void方法的调用,但是stubVoid()方法被弃用换成了doThrow(Throwable),为了与doAnswer(Answer)保持一致,对于doThrow与doAnswer会在后面12详细讲解。
6.Verification in order-验证调用顺序
Verification in order is flexible - you don‘t have to verify all interactions one-by-one but only those that you are interested in testing in order.——来自官网
Mockito对于顺序的验证是比较灵活的,你不必一一验证所有的调用,只需要验证你所需要的即可。
@Test public void testMockito6(){ List firstMock = mock(List.class); List secondMock = mock(List.class); //using mocks firstMock.add("was called first"); secondMock.add("was called second"); // 创建InOrder对象时只需要传入你所需要验证顺序的Mock对象即可 InOrder inOrder = inOrder(firstMock, secondMock); // 下面这两个是正确的,调用顺序正确 inOrder.verify(firstMock).add("was called first"); inOrder.verify(secondMock).add("was called second"); // 下面这两个会失败,因为调用的顺序出错了 inOrder.verify(secondMock).add("was called second"); inOrder.verify(firstMock).add("was called first"); }
小结:
由于篇幅过长,我将方法介绍分为了两部分,一共有十三点,后七点会在下一篇继续介绍。