什么是 Mock 测试

Mock测试就是在测试过程中,对于某些不容易构造或者不容易获取的对象,用一个虚拟的对象来创建以便测试的测试方法。什么是不容易构造的对象呢?例如HttpServletRequest,需要在有servlet容器环境中创建获取。那不容易获取的对象呢?如一个JedisCluster,需要准备redis相关环境,然后设置进去等等。

Mock 可以分解在单元测试中耦合的其他类或者接口,它能够帮你模拟这些依赖,并帮你验证所调用的依赖的行为。

场景事例

当我们需要测试OrderService时,按照我们常规的做法呢,都是要先准备好redis,跟db的环境,然后构造UserService跟CouponService注入进来,此时需要构建完整的依赖树,其过程是比较繁琐的,万一数据库连不上,依赖找不到,服务挂了... 时间一长可能会打击我们对项目进行单测的积极性,所以这时候很有必要寻求一种优雅的方式来解决。

铛铛铛~这时候Mockito出现了(java中Mock框架比较多,但是本篇只介绍这个),它会把那些繁琐的依赖统统转化为Mock Object,如下图,这样我们就可以专注的进行我们的单测,减少在解决依赖上浪费的时间了。

直接开干

关于Mockito的简介这里就不在赘述了,大家有兴趣可以自行去官方文档查阅,这里主要带大家了解一些常用的Mock方法。

maven依赖

<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>2.23.4</version>
<scope>test</scope>
</dependency>

  

为了代码测试的方便,直接在测试类中静态导入 import static org.mockito.Mockito.*;

基础方法

@Test
public void testMockBase(){
//创建ArrayList的Mock对象
List mockList = mock(ArrayList.class);
//pass
Assert.assertTrue(mockList instanceof ArrayList); //当我们mockList调用方法去add("张三")的时候会返回true
when(mockList.add("张三")).thenReturn(true);
//当我们mockList调用方法size()的时候返回10
when(mockList.size()).thenReturn(10);
//pass
Assert.assertTrue(mockList.add("张三"));
//pass
Assert.assertFalse(mockList.add("李四"));
//pass
Assert.assertEquals(mockList.size(),10);
//null
System.out.println(mockList.get(0));
}
 

mock静态方法会创建一个Mock对象,由于 Mock对象 并不会真的执行方法中的代码,所以如果未指定返回值的话会返回默认值(如19行)。第九、十行我们指定了mockList在执行特定方法后需要返回的值,所以在assertTrue校验是没问题的,但是add("李四"),我们并没设置,所以是false。

校验方法调用次数

//使用mock
List mockedList = mock(ArrayList.class);
mockedList.add("once"); mockedList.add("twice");
mockedList.add("twice"); mockedList.add("three times");
mockedList.add("three times");
mockedList.add("three times"); //这里默认是判断该方法调用times(1),同下
verify(mockedList).add("once");
verify(mockedList, times(1)).add("once"); verify(mockedList, times(2)).add("twice");
verify(mockedList, times(3)).add("three times");
//从没调用,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");
 

其实在上述的代码中,命名是比较直观的,所以我这边就直接注释在代码中了。

校验方法调用时长

//方法执行在100ms以内的时候可以通过
verify(mock, timeout(100)).someMethod();
//同上
verify(mock, timeout(100).times(1)).someMethod(); //方法2次调用均没超过100ms
verify(mock, timeout(100).times(2)).someMethod(); verify(mock, timeout(100).atLeast(2)).someMethod();
 

通过超时检测可以校验我们的方法逻辑会不会有出现问题而导致超时的地方。

参数匹配

linkedList.add("element");
// anyInt() 任何整数我们都返回 element
when(linkedList.get(anyInt())).thenReturn("element"); System.out.print(linkedList.get(10));//返回element

方法抛出异常

 @Test(expected = RuntimeException.class)
public void doThrow(){
List list = mock(List.class);
doThrow(new RuntimeException()).when(list).add(1);
list.add(1);
}

使用注解注入

  public class ArticleManagerTest {

       @Mock private ArticleCalculator calculator;
@Mock private ArticleDatabase database;
@Mock private UserProvider userProvider; private ArticleManager manager;
 

要注意的是,通过注解的方式用使用的话,我们必须在添加初始化mock的代码,不然即使标注了注解也会是null

MockitoAnnotations.initMocks(testClass);

关于Mockito更多详细的用法,大家可以直接参考官方文档,因为各种“奇技淫巧”确实比较多,后面也更新对java8 lambda的支持,很多功能还是期待大家去挖掘~

更多详细用法可直接参考官方文档:

static.javadoc.io/org.mockito…

相信当你熟练使用Mockito以后,你会爱上写单测的,也会让你代码健壮性有所加强。有些bug能提前发现的话,总比运行的时候被别人半夜叫起来修复舒服是吧?

微信公众号《深夜里的程序猿》 -  每天分享最干的干货

Java单元测试神器之Mockito的更多相关文章

  1. Java单元测试(Junit+Mock+代码覆盖率)

    微信公众号[程序员江湖] 作者黄小斜,斜杠青年,某985硕士,阿里 Java 研发工程师,于 2018 年秋招拿到 BAT 头条.网易.滴滴等 8 个大厂 offer,目前致力于分享这几年的学习经验. ...

  2. 原!!关于java 单元测试Junit4和Mock的一些总结

    最近项目有在写java代码的单元测试,然后在思考一个问题,为什么要写单元测试??单元测试写了有什么用??百度了一圈,如下: 软件质量最简单.最有效的保证: 是目标代码最清晰.最有效的文档: 可以优化目 ...

  3. java大神进阶之路

    既然励志在java路上走的更远,那就必须了解java的路径.先看图 更加细化的细节如下 一: 编程基础 不管是C还是C++,不管是Java还是PHP,想成为一名合格的程序员,基本的数据结构和算法基础还 ...

  4. Java单元测试(Junit+Mock+代码覆盖率)---------转

    Java单元测试(Junit+Mock+代码覆盖率) 原文见此处 单元测试是编写测试代码,用来检测特定的.明确的.细颗粒的功能.单元测试并不一定保证程序功能是正确的,更不保证整体业务是准备的. 单元测 ...

  5. Java Mocking入门—使用Mockito

    Java Mocking入门—使用Mockito 2014/03/10 | 分类: 基础技术 | 0 条评论 | 标签: 单元测试 分享到:8 本文由 ImportNew - liken 翻译自 dz ...

  6. [转帖]APP逆向神器之Frida【Android初级篇】

    APP逆向神器之Frida[Android初级篇] https://juejin.im/post/5d25a543e51d455d6d5358ab 说到逆向APP,很多人首先想到的都是反编译,但是单看 ...

  7. ORACLE恢复神器之ODU/AUL/DUL

    分享ORACLE数据库恢复神器之ODU.DUL和AUL工具. ODU:ORACLE DATABASE UNLOADER DUL:DATA UNLOADER AUL:也称MyDUL 关于三种工具说明: ...

  8. Java单元测试技术1

    另外两篇关于介绍easemock的文章:EasyMock 使用方法与原理剖析,使用 EasyMock 更轻松地进行测试 摘要:本文针对当前业软开发现状,先分析了WEB开发的技术特点和单元测试要解决的问 ...

  9. 转载-使用 Feed4JUnit 进行数据与代码分离的 Java 单元测试

    JUnit 是被广泛应用的 Java 单元测试框架,但是它没有很好的提供参数化测试的支持,很多测试人员不得不把测试数据写在程序里或者通过其它方法实现数据与代码的分离,在后续的修改和维护上有诸多限制和不 ...

随机推荐

  1. Maven手动添加jar包

    有的jar在Maven中找不到则需要手动添加(如ojdbc14.jar) 方法如下: 一.将你要添加的jar包放到指定目录(在该目录下打开命令窗口) 二.输入指令:mvn install:instal ...

  2. .NET开发微信小程序-微信支付

    前台MD5加密代码 /* * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message * Digest Algor ...

  3. FPA笔记三 数据功能的识别

    原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://welkinhu.blog.51cto.com/447606/115477     ...

  4. 定时器Timer的使用

    概述 Timer类的主要作用是设置计划任务,但封装任务的类却是TimerTask类.执行计划任务的代码要放入TimerTask的子类中,因为TimerTask是一个抽象类. 方法schedule(ta ...

  5. python函数调用的四种方式 --基础重点

    第一种:参数按顺序从第一个参数往后排#标准调用 # -*- coding: UTF-8 -*- def normal_invoke(x, y): print "--normal_invoke ...

  6. Get Docker CE for CentOS

    To get started with Docker CE on CentOS, make sure you meet the prerequisites, then install Docker. ...

  7. SourceTree安装跳过注册

    问题描述 SourceTree是一个可视化管理版本文件的工具,但是注册的时候需要打开外国的网站. 因此要安装时需要绕过这一步才能使用. 解决方案 1. 在下面路径下创建一个accounts.json文 ...

  8. 两个标签页定位第二个标签页元素时显示element not visible

    问题描述 web页面有两个标签页, 当转换到第二个标签页定位元素时, 显示element not visible. 代码 ... //省略 WebElement ele= browser.getEle ...

  9. Java 读书笔记 (十一) Number & Math 类

    所有的包装类(Integer.Long.Byte.Double.Float.Short)都是抽象类Number的子类. 这种由编译器特别支持的包装称为装箱,所以当内置数据类型被当作对象使用的时候,编译 ...

  10. 自动化测试基础二(Python基础)

    1.为什么学习Python 1)简单.易学 2)强大:交互性.解释性.编译性.跨平台 3)市场需求上升快.顺应市场需要 4)自动化测试需要使用编程语言来写脚本 2.需要学习Python哪些内容? 1) ...