为神马要使用Mockito?

  在编写单元测试的时候,为了尽可能的保证隔离性,我们时常需要对某些不容易构造或者不容易获取或者对外部环境有依赖的对象,用一个虚拟的对象来创建以便于测试.假设你正在开发的的代码中使用到了公司其他部门的接口(通过RPC服务),当编写单元测试的时候你可能为了不让接口真的去调用rpc服务而mock一个接口的对象,最原始的方式是自己手工编写一个该接口的实现类,并且在单元测试的时候注入这个对象,而使用Mockito则可以让我们方便地创建和配置mock对象,使用mockito可以简化对外部环境的依赖.

创建mock对象

  这里我们以一个操作Redis的工具类来举例,下面是代码:

public class RedisUtil {
@Autowired
private RedisOperations<String, String> redisTemplate;
public boolean checkKeyExists(String key) {
return redisTemplate.hasKey(key);
} public void setValueByKey(String key, String value) {
redisTemplate.opsForValue().set(key, value);
}
public String getValueByKey(String key) {
return redisTemplate.opsForValue().get(key);
} public List<String> getMutiValuesByList(List<String> keys){
return redisTemplate.opsForValue().multiGet(keys);
} public void deleteKey(String key) {
redisTemplate.delete(key);
} public void increValue(String key,Long count){
redisTemplate.opsForValue().increment(key,count);
}
}

  有两种方式可以方便的创建mock对象,第一种方式是

Mockito.mock(RedisUtil.class);

  还有一种方式在注入时使用@mock注解:

@mock
private RedisUtil redisUtil;

Tips:如果在代码中频繁的使用Mockito比较烦,可以静态导入package,以下例子全部默认已静态导入Mockito包:

import static org.mockito.Mockito.*;

为测试函数打桩的常用方法

  当对象被创建之后,就可以对代码中出现的方法进行自定义的交互,mock对象会记住这些交互,在单元测试的执行中碰到代码中的对应方法会默认执行被你自定义的方法内容.

  还是以RedisUtil为例,对方法设定返回值:

when(redisUtil.getValueByKey("key1")).thenReturn("value1");
when(redisUtil.getValueByKey("key2")).thenReturn("value2");

  对方法设定返回自定义的异常信息:

when(redisUtil.getValueByKey("key1")).thenThrow(new RuntimeException);

  此外Mockito还支持迭代风格的返回值定义:

when(redisUtil.getValueByKey("key1")).thenReturn("value1").thenReturn("Value2");

  即当方法第一次调用redis.getValueBykey("key1")时会返回value1,当再次被调用时则会返回value2.这里需要注意的是,当后续再出现调用的时候返回值都会是value2,而且这种迭代风格的定义支持return和Throw的混搭,即你可以控制在函数调用的第一次去抛出一个异常,而在函数调用的第二次绘制一个正常的值.

Mockito如何mock返回值为void的方法

   首先,测试中对于返回值为void 的方法进行mock本身是没有什么效果的,Mockito有一个doNothing方法是void方法的默认返回:

doNothing().when(redisUtil).increValue(“key1",1L);

  其实这里使用doNothing来mock这个方法并没有什么意义,因为我们mock一个方法的目的无非有两个,第一,在某一中输入环境中模拟返回我们期待的返回值,第二就是当方法抛出异常时能够在我们预期控制之下而不会导致单元测试失败,因此对于返回值为void的方法,我们一般可以不去mock它或者使用doThrow()来为void函数打一个桩,当出现异常的时候mock他的异常返回,当不会有异常发生时,只需要在调用后,verify()一下,验证方法的被调用次数即可.

verify(redisUtil,times(1)).increValue("key1",1L);

  代码中的times(1)表示一次,即代码中increValue()返回被调用一次的时候能够通过,还可以支持更加广泛的定义,

never():表示从未被调用

atleastOnce():表示至少被调用一次

atleast(3):表示至少被调用3次

atMost(7):表示最多被调用7次

参数匹配器

  这里主要介绍一下内置的几个参数匹配器,其实也很好理解,还是那上面的redisUtil为例,对于redisUtil.getValueByKey来说,我希望对于任意的key都返回同一个值,那就可以这么写:

when(redisUtil.getValueByKey(anyString()).thenReturn("value1")

  这样在单元测试过程中,对于任意的输入参数,该方法都会返回value1,相同的类型还有很多anyLong(),anyInt(),anyList()等等

使用Spy对象来监控真实对象

  以上所讲的对象都是mock对象,mock对象只能调用打桩方法,不能调用真实方法,使用Spy可以让我们能够监视一个真实对象,既可以对这个对象的某一个函数打桩返回我们期望的值,也可以去调用真实的方法,创建spy对象的方式和mock类似,不同的一点是spy需要传一个真实对象而不是一个CLass对象.这里以一个List为例,

List spy = spy(new LinkedList());
when(spy.get(0)).thenReturn("value1");
doReturn("value2").when(spy).get(0);

  上面第二行代码,调用when(spy.get(0)),会去调用真实的方法,会抛出异常,第三行代码则不会去调用真实方法,而返回value2.所以总结一下就是,当使用when去模拟返回值的时候,真是方法会被调用,而是用doReturn()去设置的话,则不会去执行真实方法.

  需要注意在使用时应该尽量避免使用spy.

参考文档

  Mockito文档

  

提升单元测试体验的利器--Mockito使用总结的更多相关文章

  1. Atitit.hybrid混合型应用 浏览器插件,控件的实现方式 浏览器运行本地程序的解决方案大的总结---提升用户体验and开发效率..

    Atitit.hybrid混合型应用 浏览器插件,控件的实现方式 浏览器运行本地程序的解决方案大的总结---提升用户体验and开发效率.. 1. hybrid App 1 1.1. Hybrid Ap ...

  2. paip.提升用户体验--radio图片选择器 easyui 实现..

    #paip.提升用户体验--radio图片选择器 easyui 实现.. =================================== ##原因... ------------------- ...

  3. paip.提升用户体验--提升java的热部署热更新能力

    paip.提升用户体验--提升java的热部署热更新能力 想让java做到php那么好的热部署能力  "fix online"/在线修复吗??直接在服务器上修改源码生效,无需重启应 ...

  4. paip.提升用户体验----gcc c++ JIT-debugging 技术

    paip.提升用户体验----gcc  c++ JIT-debugging 技术 作者Attilax ,  EMAIL:1466519819@qq.com  来源:attilax的专栏 地址:http ...

  5. paip.提升用户体验-----c++ gcc 命令在notepad++扩展中的配置..

    paip.提升用户体验-----c++ gcc 命令在notepad++扩展中的配置.. 作者Attilax ,  EMAIL:1466519819@qq.com  来源:attilax的专栏 地址: ...

  6. atitit.提升研发效率的利器---重型框架与类库的差别与设计原则

    atitit.提升研发效率的利器---重型框架与类库的差别与设计原则 1. 框架的意义---设计的复用 1 1.1. 重型框架就是it界的重武器. 1 2. 框架 VS. 库 可视化图形化 1 2.1 ...

  7. paip.提升用户体验---c++ qt 取消gcc编译的警告信息.txt

    paip.提升用户体验---c++ qt 取消gcc编译的警告信息.txt 作者Attilax ,  EMAIL:1466519819@qq.com  来源:attilax的专栏 地址:http:// ...

  8. paip.提升用户体验---论文本编辑器的色彩方案

    paip.提升用户体验---论文本编辑器的色彩方案 作者Attilax ,  EMAIL:1466519819@qq.com  来源:attilax的专栏 地址:http://blog.csdn.ne ...

  9. paip.提升用户体验---c++ qt自定义窗体(1)---标题栏的绘制

    源地址:http://blog.csdn.net/attilax/article/details/12343625 paip.提升用户体验---c++ qt自定义窗体(1)---标题栏的绘制 效果图: ...

随机推荐

  1. 在Oracle中添加用户登录名称

    第一步,打开Oracle客户端单击 “帮助”-->"支持信息"-->”TNS名“,加入红色部分.页面如下: 第二步,再次打开Oracle客户端时,就会显示数据库了,只需 ...

  2. HYML / CSS和Javascript 部分

    1  CSS实现垂直水平居中 HTML结构: <div class="wrapper"> <div class="content">&l ...

  3. 尚学堂Java第一课

    今天是北京尚学堂郑州分校开课的第一天,小班面授教学. 我很兴奋,是一个小白对IT大神渴求传道授业解惑的兴奋. 杨老师还是一贯耐心详细的手敲了第一堂课的完整大纲,必须给杨老师赞赞赞!!! 从幽默的制定班 ...

  4. [PHP] 网盘搜索引擎-采集爬取百度网盘分享文件实现网盘搜索

    标题起的太大了,都是骗人的.最近使用PHP实现了简单的网盘搜索程序,并且关联了微信公众平台.用户可以通过公众号输入关键字,公众号会返回相应的网盘下载地址.就是这么一个简单的功能,类似很多的网盘搜索类网 ...

  5. Ionic2 + Angular4 + JSSDK开发中的若干问题汇总

    前景 目前微信公众号程序开发已经相当火热,客户要求自己的系统有一个公众号,已经是一个很常见的需要. 使用公众号可以很方便的便于项目干系人查看信息和进行互动,还可以很方便录入一些电脑端不便于录入的数据, ...

  6. springboot(十):邮件服务

    springboot仍然在狂速发展,才五个多月没有关注,现在看官网已经到1.5.3.RELEASE版本了.准备慢慢在写写springboot相关的文章,本篇文章使用springboot最新版本1.5. ...

  7. IOS的UITableView

    UITableView 概述 UITableView 一般用来展示表格数据.可以滚动(继承自UIScrollView).性能极佳 UITableView分两种样式: Plain,不分组的样式 Grou ...

  8. html页面顶部出现一段空白,检查控制台发现body 下出现&#65279字符,原因及解决办法

    html页面顶部出现一段空白,检查控制台发现body 下出现&#65279字符,原因及解决办法 分析: 原来是页面编码时增加了BOM,此页面后端数据主要是PHP语言,对PHP来讲PHP在设计时 ...

  9. vue视频学习笔记03

    video 3 git page:任何仓库 master分支,都可以发布(git page)-------------------------------------双向过滤器:Vue.filter( ...

  10. hdu4681 String DP(2013多校第8场)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4681 思路: 我是胡搞过的 就是先预处理出(i,j)的正向的最大连续子串和逆向最大连续子串 然后对于A ...