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

Mockito的简单使用方法演示样例的更多相关文章

  1. CSS3中transform,transition和animation的简单介绍和使用方法演示样例

    transform是一个属性,本质跟width,height是一样的,加上transform也就是为类添加一个变换属性. transition是一个属性.它是用来控制过渡效果的,由于用transfor ...

  2. C#开发Unity游戏教程循环遍历做出推断及Unity游戏演示样例

    C#开发Unity游戏教程循环遍历做出推断及Unity游戏演示样例 Unity中循环遍历每一个数据,并做出推断 非常多时候.游戏在玩家做出推断以后.游戏程序会遍历玩家身上大量的所需数据,然后做出推断. ...

  3. Java 8 时间日期库的20个使用演示样例

    除了lambda表达式,stream以及几个小的改进之外,Java 8还引入了一套全新的时间日期API,在本篇教程中我们将通过几个简单的任务演示样例来学习怎样使用Java 8的这套API.Java对日 ...

  4. Eureka 的 Application Client client的执行演示样例

            上篇以一个 demo 演示样例介绍了 Eureka 的 Application Service 客户端角色.今天我们继续了解 Eureka 的 Application Client 客 ...

  5. C++ Primer中文本查询演示样例Query的实现

    近期在看C++ Primer复习C++的语法,看到书中15.9章中的文本查询演示样例时,认为设计得非常不错,于是便动手照着实现了一个,改动了非常久最终执行成功了,从中也学习到了非常多的语法.以下把实现 ...

  6. HBase总结(十一)hbase Java API 介绍及使用演示样例

    几个相关类与HBase数据模型之间的相应关系 java类 HBase数据模型 HBaseAdmin 数据库(DataBase) HBaseConfiguration HTable 表(Table) H ...

  7. Introspector(内省)简单演示样例 与 简单应用

    简单演示样例: package com.asdfLeftHand.test; import java.beans.BeanDescriptor; import java.beans.BeanInfo; ...

  8. JBoss 系列九十六:JBoss MSC - 简介及一个简单演示样例

    什么是 JBoss MSC JBoss MSC 即 JBoss Modular Service Container,是第三代 JBoss 产品 JBoss 7和WildFfly的内核,JBoss MS ...

  9. Thrift的安装和简单演示样例

    本文仅仅是简单的解说Thrift开源框架的安装和简单使用演示样例.对于具体的解说,后面在进行阐述. Thrift简述                                           ...

随机推荐

  1. CAD交互绘制虚线(网页版)

    用户可以在CAD控件视区任意位置绘制直线. 主要用到函数说明: _DMxDrawX::DrawLine 绘制一个直线.详细说明如下: 参数 说明 DOUBLE dX1 直线的开始点x坐标 DOUBLE ...

  2. ideal取消按下两次shift弹出搜索框 修改idea,webstrom,phpstrom 快捷键double shift 弹出search everywhere

    因为经常需要在中英文之间切换,所以时常使用shift键,一不小心就把这个Searchwhere 对话框调出来了,很是麻烦. 因此痛定思痛, 我决定将这个按两下shift键就弹出搜索框的快捷键禁用了! ...

  3. 使用Maven构建JavaEE项目

    学习要点 Maven简介 Maven构建项目 MyEclipse中Maven的使用 Maven简介 Maven作用 对第三方依赖库进行统一的版本管理 统一的目录结构,统一各平台各IDE目录 统一的软件 ...

  4. linux 查看分区UUID的两种方法

    1. sudo blkid /dev/loop0: TYPE="squashfs"/dev/loop1: TYPE="squashfs"/dev/loop2: ...

  5. Springboot 图标更换

    1.将自己的logo图片转为.ico格式的,命名必须为[favicon.ico] 2.将该图片直接放在src/main/resourecs目录下 3.重启项目,刷新一下浏览器缓存,就会发现图标更换了

  6. luogu P2078 朋友

    题目背景 小明在A公司工作,小红在B公司工作. 题目描述 这两个公司的员工有一个特点:一个公司的员工都是同性. A公司有N名员工,其中有P对朋友关系.B公司有M名员工,其中有Q对朋友关系.朋友的朋友一 ...

  7. scanf_s读取键盘输入字符串失败

    #include<stdio.h> int main() { ]; ]; printf("Input string:\n"); scanf_s("%s&quo ...

  8. 3. 对系统表空间使用Raw磁盘分区

    3. 对系统表空间使用Raw磁盘分区 可以将raw磁盘分区用作InnoDB系统表空间中的数据文件.此技术可在Windows和某些Linux和Unix系统上启用非缓冲I/O,而无需文件系统开销.使用和不 ...

  9. 如何在Python中显式释放内存?

    根据Python官方文档,您可以强制垃圾收集器释放未引用的内存gc.collect().例: import gc gc.collect() 所属网站分类: python高级 > 综合&其 ...

  10. 07 mongodb

    mongodb mongodb简介 简介 MongoDB是一个基于分布式文件存储的数据库.由C++语言编写.旨在为Web应用提供可扩展的高性能数据存储解决方案.    MongoDB是一个介于关系数据 ...