mockito 返回值怎么样Mock返回值为空的方法

Mock工具之Mockito实战
来源:博客园
在实际项目中写单元测试的过程中我们会发现需要测试的类有很多依赖,这些依赖项又会有依赖,导致在单元测试代码里几乎无法完成构建,尤其是当依赖项尚未构建完成时会导致单元测试无法进行。为了解决这类问题我们引入了Mock的概念,简单的说就是模拟这些需要构建的类或者资源,提供给需要测试的对象使用。业内的Mock工具有很多,也已经很成熟了,这里我们将直接使用最流行的Mockito进行实战演练。Mock工具概述1.1
Mockito简介 EasyMock 以及 Mockito 都因为可以极大地简化单元测试的书写过程而被许多人应用在自己的工作中,但是这两种 Mock 工具都不可以实现对静态函数、构造函数、私有函数、Final 函数以及系统函数的模拟,但是这些方法往往是我们在大型系统中需要的功能。另外,关于更多Mockito2.0新特性,参考官方介绍文档,里边有关于为什么不mock private的原因,挺有意思的:1.2 Mockito准备工作###Maven###通过Maven管理的,需要在项目的Pom.xml中增加如下的依赖: &dependencies&&dependency&&groupId&org.mockito&/groupId&&artifactId&mockito-core&/artifactId&&version&2.7.19&/version&&scope&test&/scope&&/dependency&&/dependencies&
在程序中可以import org.mockito.Mockito,然后调用它的static方法。Maven用户可以声明对mockito-core的依赖。 Mockito自动发布到Bintray的中心,并同步到Maven Central Repository。特别提醒:使用手工依赖关系管理的Legacy构建可以使用1. *“mockito-all”分发。 它可以从Mockito的Bintray存储库或Bintray的中心下载。 在但是Mockito 2. * “mockito-all”发行已经停止,Mockito 2以上版本使用“mockito-core”。官网下载中心:目前最新版本为2.7.19,由于公司网络网关问题,最好是去官网手工下载。另外Mockito需要Junit配合使用,在Pom文件中同样引入:&dependency&
&groupId&junit&/groupId&
&artifactId&junit&/artifactId&
&version&4.12&/version&
&scope&test&/scope&
&/dependency&然后为了使代码更简洁,最好在测试类中导入静态资源,还有为了使用常用的junit关键字,也要引入junit的两个类Before和Test:import static org.mockito.Mockito.*;import static org.junit.Assert.*;import org.junit.Bimport org.junit.T1.3 模拟对象创建 Mock 对象的语法为 mock(class or interface)。Mock 对象的创建mock(Class classToMock); mock(Class classToMock, String name) mock(Class classToMock, Answer defaultAnswer) mock(Class classToMock, MockSettings mockSettings) mock(Class classToMock, ReturnValues returnValues)可以对类和接口进行mock对象的创建,创建时可以为mock对象命名。对mock对象命名的好处是调试的时候容易辨认mock对象。 Mock对象的期望行为和返回值设定假设我们创建了LinkedList类的mock对象: LinkedList mockedList = mock(LinkedList.class);1.4 设置对象调用的预期返回值通过 when(mock.someMethod()).thenReturn(value) 来设定 Mock 对象某个方法调用时的返回值。我们可以看看源码中关于thenReturn方法的注释: 使用when(mock.someMethod()).thenThrow(new RuntimeException) 的方式来设定当调用某个方法时抛出的异常。 以及Answer:
Answer 是个泛型接口。到调用发生时将执行这个回调,通过
Object[] args = invocation.getArguments();可以拿到调用时传入的参数,通过 Object mock = invocation.getMock();可以拿到mock对象。有些方法可能接口的参数为一个Listener参数,如果我们使用Answer打桩,我们就可以获取这个Listener,并且在Answer函数中执行对应的回调函数,这对我们了解函数的内部执行过成有很大的帮助。使用doThrow(new RuntimeException(“clear exception”)).when(mockedList).clear();mockedList.clear();的方式Mock没有返回值类型的函数:doThrow(new RuntimeException()).when(mockedList).clear();//将会 抛出 RuntimeException:mockedList.clear();这个实例表示当执行到mockedList.clear()时,将会抛出RuntimeException。其他的doXXX执行与它类似。例如 : doReturn()|doThrow()| doAnswer()|doNothing()|doCallRealMethod() 系列方法。 Spy函数:你可以为真实对象创建一个监控(spy)对象,当你使用这个spy对象时,真实的对象也会被调用,除非它的函数被打桩。你应该尽量少的使用spy对象,使用时也需要小心,例如spy对象可以用来处理遗留代码,Spy示例如下:List list = new LinkedList();//监控一个真实对象List spy = spy(list);//你可以为某些函数打桩when(spy.size()).thenReturn(100);//使用这个将调用真实对象的函数spy.add("one");spy.add("two");//打印"one"System.out.println(spy.get(0));//size() 将打印100System.out.println(spy.size());//交互验证verify(spy).add("one"); verify(spy).add("two");理解监控真实对象非常重要,有时,在监控对象上使用when(Object)来进行打桩是不可能或者不切实际的。因为,当使用监控对象时,请考虑用doReturn、Answer、Throw()函数组来进行打桩,例如:List list = new LinkedList();List spy = spy(list);//这是不可能的: 因为调用spy.get(0)时会调用真实对象的get(0)函数,此时会发生//IndexOutOfBoundsException异常,因为真实对象是空的 when(spy.get(0)).thenReturn("foo");//你需要使用 doReturn() 来打桩doReturn("foo").when(spy).get(0);Mockito并不会为真实的对象代理函数调用,实际上它会复制真实对象,因此,如果你保留了真实对象并且与之交互,不要期望监控对象得到正确的结果。当你在监控对象上调用一个没有stub函数时,并不会调用真实对象的对应函数,你不会在真实对象上看到任何效果。1.5 验证被测试类方法Mock 对象一旦建立便会自动记录自己的交互行为,所以我们可以有选择的对它的 交互行为进行验证。在 Mockito 中验证 Mock 对象交互行为的方法是 verify(mock).someMethod(…)。最后 Assert() 验证返回值是否和预期一样。1.6 Demo 从网上找来一个最简单的代码实例,下面以具体代码演示如何使用Mockito,代码有三个类,分别如下:Person类:public class Person {
private final int
private final S
public Person(int id, String name) {
this.name =
public int getId() {
public String getName() {
}}PersonDao类:public interface PersonDao {
Person getPerson(int id);
boolean update(Person person);
}PersonService类: public class PersonService {
private final PersonDao personD
public PersonService(PersonDao personDao) {
this.personDao = personD
public boolean update(int id, String name) {
Person person = personDao.getPerson(id);
if (person == null)
{ return false; }
Person personUpdate = new Person(person.getId(), name);
return personDao.update(personUpdate);
}} 仍然使用Junit自动生成测试类或者手工新建测试类:
测试代码生成后,将默认assertfail的删掉,输入以下两个测试方法:import org.junit.Bimport org.junit.Timport static org.junit.Assert.*;import static org.mockito.Mockito.*;public class PersonServiceTest {
private PersonDao
private PersonService personS
public void setUp() throws Exception {
//模拟PersonDao对象
mockDao = mock(PersonDao.class);
when(mockDao.getPerson(1)).thenReturn(new Person(1, "Person1"));
when(mockDao.update(isA(Person.class))).thenReturn(true);
personService = new PersonService(mockDao);
public void testUpdate() throws Exception {
boolean result = personService.update(1, "new name");
assertTrue("must true", result);
//验证是否执行过一次getPerson(1)
verify(mockDao, times(1)).getPerson(eq(1));
//验证是否执行过一次update
verify(mockDao, times(1)).update(isA(Person.class));
public void testUpdateNotFind() throws Exception {
boolean result = personService.update(2, "new name");
assertFalse("must true", result);
//验证是否执行过一次getPerson(1)
verify(mockDao, times(1)).getPerson(eq(1));
//验证是否执行过一次update
verify(mockDao, never()).update(isA(Person.class));
}}注意:我们对PersonDAO进行mock,并且设置stubbing,stubbing设置如下:当getPerson方法传入1的时候,返回一个Person对象,否则默认返回空当调update方法的时候,返回true这里使用了参数匹配器:isA():Object argument that implements the given class.eq():int argument that is equal to the given value注:参数匹配的概念这里不再展开叙述。 仍然调用Junit执行单元测试代码,结果如图所示:验证了两种情况:更新id为1的Person的名字,预期:能在DAO中找到Person并更新成功更新id为2的Person的名字,预期:不能在DAO中找到Person,更新失败这里也可以查看Eclipse抛出的异常信息:Argument(s) are different! Wanted:personDao.getPerson(1);-& at PersonServiceTest.testUpdateNotFind(PersonServiceTest.java:41)Actual invocation has different arguments:personDao.getPerson(2);-& at PersonService.update(PersonService.java:8)2 单元测试与覆盖率1、Junit 2、JaCoCo 3、EclEmma2 覆盖率覆盖率如下图显示:覆盖率仍然使用JaCoCo和EclEmma:l
未覆盖代码标记为红色l
已覆盖代码会标记为绿色l
部分覆盖的代码标记为黄色颜色也可以在Eclipse中自定义设置:在Eclipse下方的状态栏窗口,有一栏“Coverage”,点击可以显示详细的代码覆盖率:如何导出为Html格式的Report:在Eclipse下方的Coverage栏鼠标右键选择“Export Session…”,在弹出窗口中选择export的目标为“Coverage Report”如下图:点击“Next”按钮后,在接下来的弹出窗口选择需要导出的session,Format类型选择“HTML report”,导出位置暂时选择为桌面,都选择之后点击“Finish”按钮就生成好了。在桌面上找到一个叫做index.html的页面就是刚刚生成好的Coverage Report:点击文件夹可以进入目录,进一步查看子文件的覆盖率:
附录:参考文档一览 Mockito官网: 5分钟了解Mockito:Mockito简单介绍及示例:Mockito浅谈:单元测试利器-Mockito 中文文档:Mockito使用指南 :http://blog.csdn.net/shensky711/article/details/JUnit+Mockito 单元测试(二):http://blog.csdn.net/zhangxin09/article/details/
免责声明:本站部分内容、图片、文字、视频等来自于互联网,仅供大家学习与交流。相关内容如涉嫌侵犯您的知识产权或其他合法权益,请向本站发送有效通知,我们会及时处理。反馈邮箱&&&&。
学生服务号
在线咨询,奖学金返现,名师点评,等你来互动Mockito.when(mockService.queryInfo(Mockito.any(QueryCod.class))).thenReturn(uInfo);
mockService为接口;
queryInfo是mockService接口里的方法;
QueryCod是方法queryInfo的入参,是一个class对象;且只有一个入参。
uInfo是方法queryInfo的执行结果,uInfo是mock的一个结果。
Mockito.when(mockQueryFacade.queryByRoleId(Mockito.anyString(),Mockito.any(QueryContext.class))).thenReturn(QueryResult);
mockQueryFacade是接口;queryByRoleId是mockQueryFacade接口里的方法;
queryByRoleId方法有两个入参,QueryResult queryByRoleId(String roleId, QueryContext context);两个入参均mock。QueryResult为查询的结果。
需要导入import static org.mockito.Mockito.*;
import static org.junit.Assert.*;
import java.util.I
import org.junit.Tmock可以模拟各种各样的对象,替代真正的对象做出希望的响应。使用mockito的方法:1、使用mock()模拟对象。//模拟LinkList的一个对象
LinkedList mockdedList = mock(LinkedList.class);//此时条用get方法,会返回null,因为还没有对方法调用的返回值做模拟。System.out.printlin(mockedList.get(99));
2、指定mock对象被调用时的返回值。a、模拟,方法调用的返回值。//模拟获取第一个元素时,返回字符串first。给特定的方法调用返回固定值,在官方说法中称stub。(stub,为屏蔽客户调用远程主机上的对象,必须提供某些方式来模拟本地对象,这种本地对象称为存根stub)when(mockedList.get(0).thenReturn("first"));//此时打印输出firstSystem.out.println(mockedList.get(0));
b、模拟,方法调用抛出异常//模拟获取第二个元素时,抛出RuntimeExceptionwhen(mockedList.get(1)).thenThrow(new RuntimeException);//此时抛出RuntimeException异常System.out.println(mockedList.get(1));没有返回值类型的方法也可以模拟异常抛出:doThrow(new RuntimeException()).when(mockedList).clear();c、模拟调用方法时的参数匹配//anyInt()匹配任何int参数,这表示参数为任何值,均返回elementwhen(mockedList.get(anyInt())).thenReturn("element");//此时打印是elementSystem.out.println(mockedList.get(99));d、模拟方法调用次数//调用add一次mockedList.add("once");//验证add方法是否被调用了一次,两种写法效果一样verify(mockedList)add("once");verify(mockedList,times(1)).add("once");还可以通过atLeast(int i)和taMost(int i)来验证被调用的次数的最小值和最大值3、验证被测试类是否正确工作,使用verify()。默认情况下,对于所有的有返回值且没有stub过的地方,mockito会返回相应的默认值,对于内置类型会返回默认值,如int会返回0,布尔值返回false,对于其他type会返回null。mock对象会覆盖整个被mock的对象,因此没有stub的方法只能返回默认值。//重复stub两次,则以第二次为准,如下将返回&second&when(mockedList.get(0)).thenReturn("first");when(mockedList.get(0)).thenReturn("second");//下面这种形式表示第一次调用返回&first&,第二次调用返回&second&,可以写n多个when(mockedList.get(0)).thenReturn("first").thenReturn("second");如果实际调用次数超过了stub过的次数,则会一直返回最后一次stub的值,如上例,第三次调用get(0),则返回 &second&验证方法被调用了特定的次数//验证add方法被调用了两次verify(mockedList,times(2)).add("2");//验证add方法致至少被调用一次verify(mockedList.atLeastOnce()).add("2");//验证add方法至少被调用两次verify(mockedList,atLeast(2)).add("2");//验证add方法最大被调用5次verify(mockedList,atMost(5)).add("2");//验证add方法从未被调用vreify(mockedList,never()).add("2");找到冗余的调用,使用never();
阅读(...) 评论()1535人阅读
Java/JEE(34)
最初接触 Mockito 还思考并尝试过如何用它来 mock 返回值为 void 的方法,然而 Google 查找到的一般都会说用&doThrow()&的办法
doThrow(new RuntimeException()).when(mockObject).methodWithVoidReturn();
因为无法使用常规的&when(mockObject.foo()).thenReturn(...)&的方法。
当时我就纳闷,为何我想 mock 一个返回值为 void 的方法,却是在模拟抛出一个异常,现在想来如果一个返回值为 void 的方法,为何要去 mock 这个方法呢?
回想一个我们要 mock 一个方法的意图是什么:
在特定输入参数的情况下期待需要的输出结果(返回值)
在方法抛出某种类型异常调用者作出的反应
对于 void 返回值的方法,如果要验证有没有被调用过几次可以在事后用&verify()&方法去断言。所以基本上对于
void 返回值的方法一般可不用去 mock 它,只需用& verify() 去验证,或者就是像前面一样模拟出现异常时的情况。
所以本文并不像是去直接回答标题所示的问题: Mockito 如何 mock& 返回值为& void 的方法,而是如何应对 mock& 对象的& void 方法&
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:179324次
积分:2653
积分:2653
排名:第13196名
原创:84篇
评论:65条
(5)(3)(11)(6)(16)(7)(3)(1)(2)(1)(1)(1)(1)(1)(14)(1)(1)(1)(1)(1)(2)(1)(1)(3)(1)(1)

我要回帖

更多关于 mockito 无返回值方法 的文章

 

随机推荐