作者|mghio

编辑|包包

前言 

在计算机编程中,单元测试是一种软件测试方法,通过该方法可以测试源代码的各个单元功能是否适合使用。为代码编写单元测试有很多好处,包括可以及早的发现代码错误,促进更改,简化集成,方便代码重构以及许多其它功能。使用 Java 语言的朋友应该用过或者听过 Junit 就是用来做单元测试的,那么为什么我们还需要 Mockito 测试框架呢?想象一下这样的一个常见的场景,当前要测试的类依赖于其它一些类对象时,如果用 Junit 来进行单元测试的话,我们就必须手动创建出这些依赖的对象,这其实是个比较麻烦的工作,此时就可以使用 Mockito 测试框架来模拟那些依赖的类,这些被模拟的对象在测试中充当真实对象的虚拟对象或克隆对象,而且 Mockito 同时也提供了方便的测试行为验证。这样就可以让我们更多地去关注当前测试类的逻辑,而不是它所依赖的对象。

生成 Mock 对象方式

要使用 Mockito,首先需要在我们的项目中引入 Mockito 测试框架依赖,基于 Maven 构建的项目引入如下依赖即可:

<dependency>   <groupId>org.mockitogroupId>    <artifactId>mockito-coreartifactId>    <version>3.3.3version>    <scope>testscope>dependency>

如果是基于 Gradle 构建的项目,则引入如下依赖:

testCompile group: 'org.mockito', name: 'mockito-core', version: '3.3.3'

使用 Mockito 通常有两种常见的方式来创建 Mock 对象。

1、使用 Mockito.mock(clazz) 方式

通过 Mockito 类的静态方法 mock 来创建 Mock 对象,例如以下创建了一个 List 类型的 Mock 对象:

List<String> mockList = Mockito.mock(ArrayList.class);

由于 mock 方法是一个静态方法,所以通常会写成静态导入方法的方式,即 List mockList = mock(ArrayList.class)。

2、使用 @Mock 注解方式

第二种方式就是使用 @Mock 注解方式来创建 Mock 对象,使用该方式创需要注意的是要在运行测试方法前使用 MockitoAnnotations.initMocks(this) 或者单元测试类上加上 @ExtendWith(MockitoExtension.class) 注解,如下所示代码创建了一个 List 类型的 Mock 对象(PS: @BeforeEach 是 Junit 5 的注解,功能类似于 Junit 4 的 @Before 注解。):

/** * @author mghio * @date: 2020-05-30 * @version: 1.0 * @description: * @since JDK 1.8 */@ExtendWith(MockitoExtension.class)public class MockitoTest {    @Mock    private List mockList;    @BeforeEach    public void beforeEach() {        MockitoAnnotations.initMocks(this);    }}

验证性测试

Mockito 测试框架中提供了 Mockito.verify 静态方法让我们可以方便的进行验证性测试,比如方法调用验证、方法调用次数验证、方法调用顺序验证等,下面看看具体的代码。

验证方法单次调用

验证方法单次调用的话直接 verify 方法后加上待验证调用方法即可,以下代码的功能就是验证 mockList 对象的 size 方法被调用一次。

/** * @author mghio * @date: 2020-05-28 * @version: 1.0 * @description: * @since JDK 1.8 */ @ExtendWith(MockitoExtension.class)public class MockitoVerifyTest {    @Mock    List mockList;    @Test    void verify_SimpleInvocationOnMock() {        mockList.size();        verify(mockList).size();    }}
验证方法调用指定次数

除了验证单次调用,我们有时候还需要验证一些方法被调用多次或者指定的次数,那么此时就可以使用 verify + times 方法来验证方法调用指定次数,同时还可以结合 atLeast + atMost 方法来提供调用次数范围,同时还有 never 等方法验证不被调用等。

/** * @author mghio * @date: 2020-05-28 * @version: 1.0 * @description: * @since JDK 1.8 */@ExtendWith(MockitoExtension.class)public class MockitoVerifyTest {  @Mock  List mockList;  @Test  void verify_NumberOfInteractionsWithMock() {    mockList.size();    mockList.size();    verify(mockList, times(2)).size();    verify(mockList, atLeast(1)).size();    verify(mockList, atMost(10)).size();  }}
验证方法调用顺序

同时还可以使用 inOrder 方法来验证方法的调用顺序,下面示例验证 mockList 对象的 size、add 和 clear 方法的调用顺序。

/** * @author mghio * @date: 2020-05-28 * @version: 1.0 * @description: * @since JDK 1.8 */ @ExtendWith(MockitoExtension.class)public class MockitoVerifyTest {    @Mock    List mockList;    @Test    void verify_OrderedInvocationsOnMock() {        mockList.size();        mockList.add("add a parameter");        mockList.clear();        InOrder inOrder = inOrder(mockList);        inOrder.verify(mockList).size();        inOrder.verify(mockList).add("add a parameter");        inOrder.verify(mockList).clear();    }}

以上只是列举了一些简单的验证性测试,还有验证测试方法调用超时以及更多的验证测试可以通过相关官方文档探索学习。

验证方法异常

异常测试我们需要使用 Mockito 框架提供的一些调用行为定义,Mockito 提供了 when(...).thenXXX(...) 来让我们定义方法调用行为,以下代码定义了当调用 mockMap 的 get 方法无论传入任何参数都会抛出一个空指针 NullPointerException 异常,然后通过 Assertions.assertThrows 来验证调用结果。

/** * @author mghio * @date: 2020-05-30 * @version: 1.0 * @description: * @since JDK 1.8 */@ExtendWith(MockitoExtension.class)public class MockitoExceptionTest {  @Mock  public Map mockMap;  @Test  public void whenConfigNonVoidReturnMethodToThrowEx_thenExIsThrown() {     when(mockMap.get(anyString())).thenThrow(NullPointerException.class);     assertThrows(NullPointerException.class, () ->    mockMap.get("mghio"));  }}

同时 when(...).thenXXX(...) 不仅可以定义方法调用抛出异常,还可以定义调用方法后的返回结果,比如 when(mockMap.get("mghio")).thenReturn(21); 定义了当我们调用 mockMap 的 get 方法并传入参数 mghio 时的返回结果是 21。这里有一点需要注意,使用以上这种方式定义的 mock 对象测试实际并不会影响到对象的内部状态,如下图所示:

虽然我们已经在 mockList 对象上调用了 add 方法,但是实际上 mockList 集合中并没有加入 mghio,这时候如果需要对 mock 对象有影响,那么需要使用 spy 方式来生成 mock 对象。

public class MockitoTest {    private List mockList = spy(ArrayList.class);    @Test    public void add_spyMockList_thenAffect() {        mockList.add("mghio");        assertEquals(0, mockList.size());    }}

断点后可以发现当使用 spy 方法创建出来的 mock 对象调用 add 方法后,mghio 被成功的加入到 mockList 集合当中。

- - - -未完待续-- - -

喜欢本文的朋友,欢迎关注公众号  并发编程网,收看更多精彩内容

mockito mock void方法_一文让你快速上手 Mockito 单元测试框架(上)相关推荐

  1. mockito mock void方法_一文让你快速上手 Mockito 单元测试框架

    前言 在计算机编程中,单元测试是一种软件测试方法,通过该方法可以测试源代码的各个单元功能是否适合使用.为代码编写单元测试有很多好处,包括可以及早的发现代码错误,促进更改,简化集成,方便代码重构以及许多 ...

  2. mockito mock void方法_用过举手!SpringBoot 单元测试利器Mockito

    Mockito 是一种 Java mock 框架,他主要是用来做 mock 测试的,他可以模拟任何 Spring 管理的 bean.模拟方法的返回值.模拟抛出异常...等,在了解 Mockito 的具 ...

  3. mockito mock void方法_使用 Junit + Mockito 实践单元测试!

    一.前言 相信做过开发的同学,都多多少少写过下面的代码,很长一段时间我一直以为这就是单元测试... @SpringBootTest @RunWith(SpringRunner.class) publi ...

  4. mockito mock void方法_纯干货,浅谈Mockito在单元测试中的实际应用

    本文接上文"接口方没写代码,对接方只能停工吗?",在这里简单介绍Mockito在单元测试中的实际应用.本文使用场景较单一,如有雷同,不甚荣幸,闲言少叙,开门见山.本文将使用mock ...

  5. mockito mock void方法_Spock如何模拟抽象类方法

    我们平时写单元测试时经常会遇到调用抽象类或父类的方法,这些抽象方法可能是调用底层接口或数据库,需要mock掉,让抽象方法返回一个我们指定的值,以便测试当前代码逻辑的场景. 下面讲下Spock如何结合p ...

  6. java mock void_如何使用Mockito模拟void方法 - How to mock void methods with Mockito

    问题: How to mock methods with void return type? 如何用void返回类型模拟方法? I implemented an observer pattern bu ...

  7. 如何使用Mockito模拟void方法

    如何用void返回类型模拟方法? 我实现了一个观察者模式,但是我不能用Mockito模拟它,因为我不知道怎么做. 我试图在互联网上找到一个例子,但没有成功. 我的课看起来像这样: public cla ...

  8. Mockito测试void方法会引发异常

    本文翻译自:Mockito test a void method throws an exception I have a method with a void return type. 我有一个vo ...

  9. php方法帮助文档,Trace方法_帮助文档_Thinkphp手册

    Trace方法_帮助文档_Think 页面Trace只能用于有页面输出的情况,但是trace方法可以用在任何情况,而且trace方法可以用于AJAX等操作. Trace方法的格式:trace('变量' ...

最新文章

  1. c#操作oracle的通用类
  2. 深度稳定学习:因果学习的最新进展 | 清华大学团队 CVPR 研究
  3. [团队公告]博客园的敏捷软件开发团队成立了
  4. C语言用DFS实现找到图的所有路径(邻接矩阵实现)
  5. javafx中的tree_JavaFX中的塔防(5)
  6. Paxos算法(Basic Paxos 与 Multi-Paxos思想)
  7. STM32单片机低功耗配置
  8. Linux中配置ftp服务器
  9. 全球知名大学课件下载地址汇总
  10. 你向 MySQL 插入 100万 条数据用了多久?
  11. 笔记.cloudflare 的橙色云代理ssl坑
  12. ws2812B+单片机驱动
  13. 微服务社交平台项目【十次方】(二)-API文档与模拟数据接口
  14. Docker安装指定版本异常:Error: Package: docker-ce-17.03.1.ce-1.el7.centos.x86_64 (docker-ce-stable)
  15. 如何系统得对目标检测模型的误差分析?
  16. linux创建分区大小命令,Linux使用fdisk创建分区详解
  17. 消息钩子使用教程(转)
  18. kali linux 修改用户名密码
  19. DevpTips_mouse without borders:去掉某个键,避免和另存为快捷键冲突
  20. Python C/S 网络编程(三)之 TCP 实现远程骰宝游戏

热门文章

  1. app测试流程和重点_APP开发测试流程是怎么样的?
  2. python写表格_使用Python对Excel进行读写操作
  3. django mysql开发_【python-Django开发】Django 配置MySQL数据库讲解!!!
  4. linux之cut命令详解
  5. nginx mysql占用率高_nginx/mysql查看内存占用
  6. Java里main的写法_main方法的深入理解和例子
  7. 小程序如何用data的数据控制页面展示_17. 教你零基础搭建小程序:小程序事件绑定(1)
  8. win10网络不出现计算机列表,win10网络发现已关闭网络计算机和设备不可见怎么办?...
  9. 公司inur php id_,PHP——个人信息管理系统
  10. linux ipv6 组播地址,ipv6组播地址是什么意思