Mockito的简单用法示例

Mockito是一个流行的Mocking框架。它使用起来简单,学习成本很低,而且具有非常简洁的API,测试代码的可读性很高。因此它十分受欢迎,用 户群越来越多,很多的开源的软件也选择了Mockito。要想了解更多有关Mockito的信息,请访问它的官方网 站:http://mockito.org/

一、简单示例

/*
 * Creation : 2015年8月14日
 */
package com.tan.test;

import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;

import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.InOrder;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;

import edu.emory.mathcs.backport.java.util.LinkedList;

public class MockitoTest {
    /**
     * 通过when(mock.someMethod()).thenReturn(value) 来设定mock对象某个方法调用时的返回值
     */
    @Test
    public void simpleTest() {
        // arrange
        Iterator i = mock(Iterator.class);
        when(i.next()).thenReturn("Hello").thenReturn("World");
        // act
        String result = i.next() + " " + i.next();
        // 验证i.next()是否被调用了2次,不关心返回值
        verify(i, times(2)).next();
        // 断言结果是否和预期一样
        assertEquals("Hello World", result);
    }

    /**
     * 参数匹配器--Argument matchers test.
     */
    @Test
    public void argumentMatchersTest() {
        List<String> mock = mock(List.class);
        // anyInt()参数匹配器来匹配任何的int 类型的参数
        when(mock.get(anyInt())).thenReturn("Hello").thenReturn("World");

        // 所以当第一次调用get方法时输入任意参数为100方法返回”Hello”,第二次调用时输入任意参数200返回值”World”。
        String result = mock.get(100) + " " + mock.get(200);

        // verfiy 验证的时候也可将参数指定为anyInt()匹配器,那么它将不关心调用时输入的参数的具体参数值。
        verify(mock, times(2)).get(anyInt());
        assertEquals("Hello World", result);
        /* 注意:如果使用了参数匹配器,那么所有的参数需要由匹配器来提供,否则将会报错。 */
    }

    /**
     * 参数匹配器--Argument matchers test2.
     */
    @SuppressWarnings("unchecked")
    @Test
    public void argumentMatchersTest2() {
        Map<Integer, String> mapMock = mock(Map.class);
        when(mapMock.put(anyInt(), anyString())).thenReturn("world");
        mapMock.put(1, "hello");
        // 注:在最后的验证时如果只输入字符串”hello”是会报错的,必须使用Matchers 类内建的eq方法。
        // 如果将anyInt()换成1进行验证也需要用eq(1)。
        verify(mapMock).put(anyInt(), eq("hello"));
    }

    /**
     * 3.Mock对象的行为验证--Verify test.
     */
    @Test
    public void verifyTest() {
        List<String> mock = mock(List.class);
        List<String> mock1 = mock(List.class);

        when(mock.get(0)).thenReturn("hello");
        mock.get(0);
        mock.get(1);
        mock.get(2);
        mock1.get(0);
        /* 方法的调用不关心是否模拟了get(2)方法的返回值,只关心mock 对象后,是否执行了mock.get(2),如果没有执行,测试方法将不会通过。 */
        verify(mock).get(2); // 验证对象mock是否调用了get(2)方法
        verify(mock, never()).get(3); // 方法中可以传入never()方法参数来确认mock.get(3)方法不曾被执行过
        /* 确认mock1对象没有进行任何交互===>测试不通过 */
        verifyNoMoreInteractions(mock1); // 将其放在 mock1.get(0);之前即可通过。
    }

    /**
     * 验证方法的调用顺序.
     */
    @Test
    public void testInvokeOrder() {
        List<String> firstMock = mock(List.class);
        List<String> secondMock = mock(List.class);

        firstMock.add("was called first");
        firstMock.add("was called first");
        secondMock.add("was called second");
        secondMock.add("was called third");

        /* 如果mock方法的调用顺序和InOrder中verify的顺序不同,那么测试将执行失败。 */

        InOrder inOrder = inOrder(secondMock, firstMock);
        inOrder.verify(firstMock, times(2)).add("was called first");
        inOrder.verify(secondMock).add("was called second");
        // 因为在secondMock.add("was called third")之后已经没有多余的方法调用了。
        inOrder.verify(secondMock).add("was called third");
        inOrder.verifyNoMoreInteractions();// 表示此方法调用后再没有多余的交互
    }

    /**
     * 自定义Answer接口(方法预期回调接口)的应用
     */

    @Test
    public void customAnswerTest() {
        List<String> mock = mock(List.class);
        when(mock.get(4)).thenAnswer(new Answer() {
            public String answer(InvocationOnMock invocation) throws Throwable {
                Object[] args = invocation.getArguments();
                Integer num = (Integer) args[0];
                if (num > 3) {
                    return "yes";
                }
                throw new RuntimeException();
            }
        });
        System.out.println(mock.get(4));
    }

    /**
     * 利用ArgumentCaptor(参数捕获器)捕获方法参数进行验证
     */
    @Test
    public void argumentCaptorTest() {
        List mock = mock(List.class);
        List mock2 = mock(List.class);
        mock.add("John");
        mock2.add("Brian");
        mock2.add("Jim");
        /*
         * 首先构建ArgumentCaptor需要传入捕获参数的对象,例子中是String。接着要在 verify 方法的参数中调用argument.capture()方法来捕获输入的参数, <br> 之后
         * argument变量中就保存了参数值,可以用argument.getValue()获取。
         */
        ArgumentCaptor argument = ArgumentCaptor.forClass(String.class);
        verify(mock).add(argument.capture());
        assertEquals("John", argument.getValue());
        verify(mock2, times(2)).add(argument.capture());

        assertEquals("Jim", argument.getValue());
        /* argument.getAllValues(),它将返回参数值的List。 */
        assertArrayEquals(new Object[] { "John", "Brian", "Jim" }, argument.getAllValues().toArray());
    }

    /**
     * Spy-对象的监视<br>
     * Mock 对象只能调用stubbed 方法,调用不了它真实的方法。但Mockito 可以监视一个真实的对象,这时对它进行方法调用时它将调用真实的方法,<br>
     * 同时也可以stubbing 这个对象的方法让它返回我们的期望值。另外不论是否是真实的方法调用都可以进行verify验证。<br>
     * 和创建mock对象一样,对于final类、匿名类和Java的基本类型是无法进行spy的。
     */
    @Test
    public void spyTest2() {
        List list = new LinkedList();
        List spy = spy(list);
        // optionally, you can stub out some methods:
        when(spy.size()).thenReturn(100);
        // using the spy calls real methods
        spy.add("one");
        spy.add("two");
        // prints "one" - the first element of a list
        System.out.println(spy.get(0));
        // size() method was stubbed - 100 is printed
        System.out.println(spy.size());
        // optionally, you can verify
        verify(spy).add("one");
        verify(spy).add("two");
    }

}

二、注解用法

Mockito对Annotation的支持

Mockito 支持对变量进行注解,例如将mock 对象设为测试类的属性,然后通过注解的方式@Mock 来定义它,这样有利于减少重复代码,增强可读性,易于排查错误等。除了支持@Mock,Mockito支持的注解还有@Spy(监视真实的对象),@Captor(参数捕获器),@InjectMocks(mock对象自动注入)。

Annotation的初始化只有Annotation还不够,要让它们工作起来还需要进行初始化工作。初始化的方

法为:MockitoAnnotations.initMocks(testClass)参数testClass是你所写的测试类。一般情况下在Junit4的@Before 定义的方法中执行初始化工作,如下:

@Before
public void initMocks() {
MockitoAnnotations.initMocks(this);
}

除了上述的初始化的方法外,还可以使用Mockito 提供的Junit Runner:

MockitoJUnitRunner这样就省略了上面的步骤。

@RunWith(MockitoJUnit44Runner.class)
public class ExampleTest {
...
}

@Mock 注解

使用@Mock注解来定义mock对象有如下的优点:

1. 方便mock对象的创建

2. 减少mock对象创建的重复代码

3. 提高测试代码可读性

4. 变量名字作为mock对象的标示,所以易于排错

@Mock注解也支持自定义name 和answer属性。下面是官方给出的@Mock使用的例子:

public class ArticleManagerTest extends SampleBaseTestCase {
@Mock
private ArticleCalculator calculator;
@Mock(name = "dbMock")
private ArticleDatabase database;
@Mock(answer = RETURNS_MOCKS)
private UserProvider userProvider;
private ArticleManager manager;
@Before
public void setup() {
manager = new ArticleManager(userProvider, database,
calculator);
}
}
public class SampleBaseTestCase {
@Before
public void initMocks() {
MockitoAnnotations.initMocks(this);
}
}

@Spy 注解

Spy的使用方法请参阅前面的章节,在此不再赘述,下面是使用方法:

public class Test{
@Spy
Foo spyOnFoo = new Foo();
@Before
public void init(){
MockitoAnnotations.initMocks(this);
}
...
}

@Captor 注解

@Captor是参数捕获器的注解,有关用法见前章,通过注解的方式也可以更便捷

的对它进行定义。使用例子如下:

public class Test {
@Captor
ArgumentCaptor<AsyncCallback<Foo>> captor;
@Before
public void init() {
MockitoAnnotations.initMocks(this);
}
@Test
public void shouldDoSomethingUseful() {
// ...
verify(mock.doStuff(captor.capture()));
assertEquals("foo", captor.getValue());
}
}

@InjectMocks 注解

通过这个注解,可实现自动注入mock 对象。当前版本只支持setter 的方式进行

注入,Mockito 首先尝试类型注入,如果有多个类型相同的mock 对象,那么它

会根据名称进行注入。当注入失败的时候Mockito不会抛出任何异常,所以你可

能需要手动去验证它的安全性。

例:

@RunWith(MockitoJUnit44Runner.class)
public class ArticleManagerTest {
@Mock
private ArticleCalculator calculator;
@Mock
private ArticleDatabase database;
@Spy
private UserProvider userProvider = new ConsumerUserProvider();
@InjectMocks
private ArticleManager manager = new ArticleManager();
@Test
public void shouldDoSomething() {
manager.initiateArticle();
verify(database).addListener(any(ArticleListener.class));
}
}

上例中, ArticleDatabase 是ArticleManager 的一个属性, 由于

ArticleManager 是注解@InjectMocks 标注的,所以会根据类型自动调用它的

setter方法为它设置ArticleDatabase

时间: 2024-10-06 21:35:00

Mockito的简单用法示例的相关文章

GO的MAP字典简单用法示例

package main import "fmt" type PersonInfo struct { ID string Name string Address string } func main() { var personDB map[string]PersonInfo personDB = make(map[string]PersonInfo) personDB["12345"] = PersonInfo{"12345", "T

sed简单用法示例

sed -n '11,$s/.*/&aaa/p' passwd 在11行至最后一行每行行尾添加aaa "&"表示正则表达式匹配的字符串 sed -nr '$s/(\w+)(.*\W)(\w+)/\3\2\1/p' 将最后一行中第一个单词和最后一个单词调换位置 "\w"表示A-Z,a-z,0-9,_中任意一个,"\W"与"\w"相反,"\3\2\1"表示圆括号中匹配的字符,第一个括号的字  

wxpython布局管理部件wx.gridbagsizer用法示例

text = ("This is text box")         panel = wx.Panel(self, -1)         chkAll1 = wx.CheckBox(panel, ID_CHKBOX_CAN_SEL_ALL, u'全选')                chkKnown = wx.CheckBox(panel, ID_CHKBOX_CAN_UNKNOWN, u'不会')         chkUnknow = wx.CheckBox(panel, I

C#中HashTable的用法示例2

命名空间 System.Collections 名称 哈希表(Hashtable) 描述 用于处理和表现类似keyvalue的键值对,其中key通常可用来快速查找,同时key是区分大小写:value用于存储对应于key的值.Hashtable中keyvalue键值对均为object类型,所以Hashtable可以支持任何类型的keyvalue键值对. 二,哈希表的简单操作 Hashtable hshTable = new Hashtable(); //  创建哈希表hshTable .Add("

泛型的简单用法&lt;T&gt;

1 private void Form1_Load(object sender, EventArgs e) 2 { 3 Print<string>("here"); 4 Print<int>(1222); 5 6 GenericCollections<string> gcl = new GenericCollections<string>(); 7 gcl.Add("这是一个字符串的示例"); 8 DisplayRes

C#中HashTable的用法示例1

一,哈希表(Hashtable)简述 在.NET Framework中,Hashtable是System.Collections命名空间提供的一个容器,用于处理和表现类似keyvalue的键值对,其中key通常可用来快速查找,同时key是区分大小写:value用于存储对应于key的值.Hashtable中keyvalue键值对均为object类型,所以Hashtable可以支持任何类型的keyvalue键值对. 二,哈希表的简单操作 在哈希表中添加一个keyvalue键值对:HashtableO

爬虫 requests,bs4 用法示例

requests 模块 用法 import requests # 1. 方法""" requests.get requests.post requests.put requests.delete ... requests.request(method='POST') """ # 2. 参数 """ 2.1 url 2.2 headers 2.3 cookies 2.4 params 2.5 data,传请求体 req

WPF 高性能位图渲染 WriteableBitmap 及其高性能用法示例

原文:WPF 高性能位图渲染 WriteableBitmap 及其高性能用法示例 WPF 渲染框架并没有对外提供多少可以完全控制渲染的部分,目前可以做的有: D3DImage,用来承载使用 DirectX 各个版本渲染内容的控件 WriteableBitmap,通过一段内存空间来指定如何渲染一个位图的图片 HwndHost,通过承载一个子窗口以便能叠加任何种类渲染的控件 本文将解释如何最大程度压榨 WriteableBitmap 在 WPF 下的性能. 本文内容 如何使用 WriteableBi

hydra简单使用示例

本内容为网上收集整理,仅作为备忘!! hydra简单使用示例: 破解https: # hydra -m /index.php -l muts -P pass.txt 10.36.16.18 https 破解teamspeak: # hydra -l 用户名 -P 密码字典 -s 端口号 -vV ip teamspeak 破解cisco: # hydra -P pass.txt 10.36.16.18 cisco # hydra -m cloud -P pass.txt 10.36.16.18 c