Java 单元测试模拟框架-Mockito 的介绍

Mockito 是什么

Mockito 是一个用于单元测试的模拟框架,基于它可以使用简洁易用的API编写出色的测试。

Mockito 允许开发人员创建和管理模拟对象(mock objects),以便在测试过程中替换那些不容易构造或获取的对象。

Mockito的基本概念

  1. Mock对象:在调试期间用来作为真实对象的替代品。通过模拟对象,可以模拟外部依赖、交互行为等,从而使测试更加独立和可控。
  2. Mock测试:在测试过程中,对那些不容易构建的对象用一个虚拟对象来代替测试的方法就叫mock测试。
  3. Stub:存根,即为mock对象的方法指定返回值(可抛出异常)。
  4. Verify:行为验证,验证指定方法调用情况(是否被调用,调用次数等)。

Mockito的主要功能

  1. 模拟方法行为:Mockito允许对模拟对象的方法进行stubbing,即定义当调用某个方法时应该返回的值或抛出的异常。
  2. 验证交互行为:Mockito提供了丰富的API来验证模拟对象的交互行为,例如方法是否被调用、调用次数、参数匹配等。
  3. 参数匹配器:Mockito提供了参数匹配器,允许在验证方法调用时使用通配符或自定义匹配规则。
  4. 部分模拟:使用@Spy注解可以创建一个部分模拟对象,允许选择性地模拟对象中的某些方法。

选择Mockito作为模拟框架的原因

  • StackOverflow庞大的社区将Mockito评为Java的最佳模拟框架
  • 在2013年末对30,000个GitHub项目进行分析时,Mockito在所有库(不仅仅是测试工具)中位列前10名Java库。尽管Mockito在主报告中排名第九,但mockito-core和mockito-all是同一工具,因此Mockito的实际排名是第四,超过了诸如Guava或Spring等著名工具。将此研究视为Mockito每天对用Java编写的单元测试产生巨大影响的指标。
  • 行为驱动开发(BDD)的创始人Dan North在2008年写道:"我们在主要会议期间决定使用JUnit 4和Mockito,因为我们认为它们是Java中TDD和模拟的未来。"

基于Maven 如何使用Mockito:

Mockito的使用步骤

  1. 添加依赖:在项目的构建文件(如Maven的pom.xml或Gradle的build.gradle)中添加Mockito的依赖。
  2. 设置测试类:使用@RunWith(MockitoJUnitRunner.class)注解测试类,或使用MockitoAnnotations.initMocks(this)在@Before方法中初始化模拟对象。
  3. 创建模拟对象:使用@Mock注解创建模拟对象,或使用Mockito.mock(Class)方法。
  4. 设置模拟行为:使用when(...).thenReturn(...)或doReturn(...).when(...)等方法设置模拟对象的行为。
  5. 编写测试方法:在测试方法中调用被测对象的方法,并使用verify(...)等方法验证交互行为。
  6. 运行测试:使用JUnit运行测试,并查看测试结果。

Mockito当前的最新版本是 5.14.2,在pom.xml中导入之后就可以开始使用了。

<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <version>5.14.2</version>
</dependency>

使用场景1: 验证交互行为, 模拟方法是否被调用了?

创建Mock对象, 验证对象的方法是否被调用了。

/**
 * Copyright (C)  Oscar Chen(XM):
 * 
 * Date: 2024-12-01
 * Author: XM
 */
package com.osxm.test.mock;

import static org.mockito.Mockito.*; // 导入Mockito的静态方法

import java.util.List;

import org.junit.jupiter.api.Test;

public class MockitoTest {

    @Test
    public void mockitoDemo() {

        // 创建mock对象
        List mockedList = mock(List.class); // 创建一个List接口的mock对象
        // 或者在Mockito 4.10.0及以上版本中,使用更简洁的方式
        // List mockedList = mock();

        // 使用mock对象,它不会抛出任何"意外交互"异常
        mockedList.add("one");
        mockedList.clear();

        // 选择性、明确且高度可读的验证
        verify(mockedList).add("one"); // 验证mock对象调用了add方法并传入了"one"
        verify(mockedList).clear(); // 验证mock对象调用了clear方法

    }

}

使用场景2:模拟方法调用

模拟方法执行返回的结果。

    @Test
    public void mockMethodCall(){
        // 不仅可以模拟接口,还可以模拟具体类
        LinkedList mockedList = mock(LinkedList.class); // 创建一个LinkedList类的mock对象
        // 或者在Mockito 4.10.0及以上版本中,使用更简洁的方式
        // LinkedList mockedList = mock();

        // 在实际执行之前进行模拟(stubbing)
        when(mockedList.get(0)).thenReturn("first"); // 当调用mockedList的get(0)方法时,返回"first"

        // 以下打印输出为"first"
        System.out.println(mockedList.get(0));

        // 以下打印输出为"null",因为get(999)方法没有被模拟
        System.out.println(mockedList.get(999));
    }

主要参考

  • mock()方法,或者 @Mock注解: 创建模拟对象
  • when()/given() 指定模拟对象的行为
  • spy()/@Spy 部门模拟, 真实方法会呼叫并且可以被验证和存根
  • @InjectMocks:自动注入用@Spy或@Mock注解的模拟/间谍字段
  • verify() : 检查方法是否使用给定参数被调用
    • 可以使用灵活的参数匹配,例如通过any()匹配任意表达式
    • 或者使用@Captor捕获被调用的参数
  • 可以使用BDDMockito进行行为驱动开发语法

Mockito的常用注解

  1. @RunWith:用于指定JUnit测试的运行器。对于Mockito,通常使用@RunWith(MockitoJUnitRunner.class)来运行测试。
  2. @Mock:用于创建模拟对象。
  3. @InjectMocks:用于将模拟对象注入到被测对象中。
  4. @Spy:用于创建部分模拟对象。

使用注意

不要干什么:

  • 不要模拟不属于你的类型
  • 不要模拟值对象
  • 不要模拟一切
  • 对测试表现一些爱心

不能干什么:

  1. 不能Mock静态方法:Mockito不支持对静态方法进行mock。
  2. 不能Mock private方法:Mockito不支持对private方法进行mock。
  3. 不能Mock final class:Mockito不支持对final类进行mock。

Mockito的集成与扩展

  1. 与JUnit集成:Mockito可以与JUnit无缝集成,使用@RunWith(MockitoJUnitRunner.class)即可。
  2. 与Spring集成:在Spring Boot项目中,可以使用@MockBean注解来模拟Spring上下文中的对象。
  3. 扩展功能:Mockito提供了丰富的扩展功能,如Mockito-inline用于支持内联Mocks的创建和使用等。

参考

相关推荐
两个人的幸福online38 分钟前
记录一次 用php 调用ai用stream返回
开发语言·php
漂流瓶6666661 小时前
Scala的模式匹配变量类型
开发语言·后端·scala
夏天吃哈密瓜1 小时前
Scala中的正则表达式01
大数据·开发语言·后端·正则表达式·scala
2401_833788051 小时前
Scala的模式匹配(2)
java·开发语言
Lbs_gemini06031 小时前
C++研发笔记14——C语言程序设计初阶学习笔记12
c语言·开发语言·c++·笔记·学习
ac-er88882 小时前
GD库如何根据颜色生成纯色背景图
开发语言·php
悠悠龙龙3 小时前
框架模块说明 #05 权限管理_03
java·开发语言·spring
开心羊咩咩4 小时前
Idea 2024.3 突然出现点击run 运行没有反应,且没有任何提示。
java·ide·intellij-idea
waterme1onY4 小时前
IDEA中MAVEN的一些设置问题
java·maven·intellij-idea
阿华的代码王国4 小时前
【算法】——前缀和(矩阵区域和详解,文末附)
java·开发语言·算法·前缀和