首页 > 代码库 > Mockito-方法介绍(一)

Mockito-方法介绍(一)

前言
    上一篇的《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");
	}



小结:
     由于篇幅过长,我将方法介绍分为了两部分,一共有十三点,后七点会在下一篇继续介绍。

Mockito-方法介绍(一)