深入了解Mockito:Java单元测试的利器

概述

单元测试在 Java 开发中的重要性不言而喻,但有些时候,面对高高的屎山,复杂的依赖,在本地根本无法执行单元测试,这个时候,就需要 Mockito 来救急了。

Mockito是一个流行的Java库,用于创建测试中的模拟对象(mock objects)。它是在单元测试中用于隔离被测试的代码,以便对其进行独立测试。Mockito的主要功能是简化和增强测试的可读性和可维护性。

基本概念

  • 模拟对象(Mock Object): 模拟对象是一个虚拟的对象,它模拟了实际对象的行为。通过模拟对象,你可以控制被测对象的依赖行为。

  • 桩(Stubbing): 这是指为模拟对象的方法设置预定义的行为。例如,当调用某个方法时,返回指定的值。

  • 验证(Verification): 验证是指检查模拟对象的方法是否按照预期被调用。

依赖说明

本文章主要用的依赖如下:

<dependency>  <groupId>org.junit.jupiter</groupId>  <artifactId>junit-jupiter-api</artifactId>  <version>3.6.28</version><scope>test</scope>  
</dependency>  
<dependency>  <groupId>org.mockito</groupId>  <artifactId>mockito-core</artifactId>  <version>3.6.28</version><scope>test</scope>  
</dependency>  
<dependency>  <groupId>org.mockito</groupId>  <artifactId>mockito-junit-jupiter</artifactId>  <version>3.6.28</version><scope>test</scope>  
</dependency>

这些依赖项是用于Java项目的单元测试框架和库,主要涉及JUnit 5和Mockito。以下是对每个依赖项的详细讲解:

1. JUnit Jupiter API

<dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter-api</artifactId><scope>test</scope>
</dependency>
  • 功能: junit-jupiter-api是JUnit 5的核心模块之一,提供了编写测试的API。它包含了JUnit 5中所有的测试注解和断言功能,如@Test@BeforeEach@AfterEach@BeforeAll@AfterAll等。

  • 使用场景: 这个依赖是编写JUnit 5测试用例的基础,提供了定义和组织测试的基本框架。

  • 测试范围: 由于其scope被设置为test,它仅在测试编译和执行时可用,不会被打包到生产代码中。

2. Mockito Core

<dependency><groupId>org.mockito</groupId><artifactId>mockito-core</artifactId><version>3.12.4</version><scope>test</scope>
</dependency>
  • 功能: mockito-core是Mockito的核心库,提供了创建和管理模拟对象的功能。它支持模拟对象、设置桩行为、验证方法调用等。

  • 使用场景: 在单元测试中使用Mockito来隔离被测对象的依赖,确保测试的独立性和可控性。它使得测试只关注被测对象的逻辑,而不是其依赖的复杂实现。

  • 版本: 版本号3.12.4表明这是一个与Java 8兼容的版本,适合在Java 8环境下使用。

  • 测试范围: 同样由于其scope设置为test,它仅在测试期间可用。

3. Mockito JUnit Jupiter

<dependency><groupId>org.mockito</groupId><artifactId>mockito-junit-jupiter</artifactId><scope>test</scope>
</dependency>
  • 功能: mockito-junit-jupiter是一个集成模块,专门用于将Mockito与JUnit 5结合使用。它提供了MockitoExtension,使得Mockito的注解(如@Mock@InjectMocks)能够在JUnit 5环境中自动初始化。

  • 使用场景: 当你使用JUnit 5进行测试时,这个模块可以简化Mockito的使用,自动处理注解的初始化,减少手动调用MockitoAnnotations.initMocks(this)的需要。

  • 测试范围: 由于其scope设置为test,它仅在测试期间可用。

总结

这些依赖项共同构成了一个强大的测试环境:

  • JUnit Jupiter API提供了测试框架的基础。
  • Mockito Core提供了模拟和验证功能。
  • **Mockito JUnit Jupiter**简化了MockitoJUnit 5的集成。

通过组合使用这些库,开发者可以编写高效、可维护的单元测试,确保代码的质量和稳定性。

基本使用步骤

  1. 第一步:创建模拟对象,使用Mockito.mock()方法可以创建一个模拟对象。
  2. 第二步:模拟对象行为,使用when()thenReturn()方法可以设置方法的返回值。
  3. 第三步:使用模拟对象,可以对结果进行验证或执行其他行为。
import org.junit.jupiter.api.Test;  
import org.mockito.Mockito;  
import java.util.List;  
import static org.mockito.Mockito.when;  
public class MockTest {  @Test  public void test(){  // 1.创建模拟对象  List<String> list = Mockito.mock(List.class);  // 2.模拟对象行为  when(list.get(0)).thenReturn("the first element");  when(list.get(1)).thenReturn("the two element");  when(list.get(2)).thenThrow(new IndexOutOfBoundsException());  // 3.使用对象  System.out.println(list.get(0));  System.out.println(list.get(1));  System.out.println(list.get(2));  }  
}

@Mock注解模拟对象

在上面,我们展示了通过Mockito.mock()方法创建模拟对象的一种方式,除此方式之外,还可以通过@Mock注解的形式进行模拟。

@Mock注解是Mockito框架中用于简化模拟对象创建的一种方式。它通过注解的方式来声明一个模拟对象,而不是通过显式调用Mockito.mock()方法。这种方式使得测试代码更加简洁和易于维护。

使用步骤

  1. 对要模拟的对象加上@Mock注解
  2. 注解初始化
    1. JUnit 4中,必须在测试方法运行之前调用MockitoAnnotations.initMocks(this)来初始化带有@Mock注解的字段.
    2. JUnit 5中,通过MockitoExtension自动处理。
      JUnit 5使用示例
import org.junit.jupiter.api.Test;  
import org.junit.jupiter.api.extension.ExtendWith;  
import org.mockito.Mock;  
import org.mockito.junit.jupiter.MockitoExtension;  
import java.util.List;  
import static org.mockito.Mockito.when;  
@ExtendWith(MockitoExtension.class)  
public class MockTest {  // 1.创建模拟对象  @Mock  List<String> list ;  @Test  public void test(){  // 2.模拟对象行为  when(list.get(0)).thenReturn("the first element");  when(list.get(1)).thenReturn("the two element");  when(list.get(2)).thenThrow(new IndexOutOfBoundsException());  // 3.使用对象  System.out.println(list.get(0));  System.out.println(list.get(1));  System.out.println(list.get(2));  }  
}

@InjectMocks注解依赖注入

@InjectMocks注解是Mockito框架中的一个强大工具,用于自动将模拟对象(通常由@Mock注解创建的)注入到被测对象的实例中。它帮助简化依赖注入的过程,使得测试代码更加简洁和易于维护。以下是对@InjectMocks注解的详细讲解:

基本概念

  • 自动注入@InjectMocks用于创建一个类的实例,并自动将标记为@Mock的模拟对象注入到该实例的字段中。它支持构造函数注入、setter方法注入以及字段注入。

  • 依赖管理: 通过使用@InjectMocks,你可以在测试中管理被测对象的依赖,而不需要手动编写注入逻辑。

使用步骤

  1. 声明被测对象: 使用@InjectMocks注解声明一个类的实例(被测对象)。

  2. 声明依赖对象: 使用@Mock注解声明被测对象的依赖。

  3. 初始化注解: 使用MockitoAnnotations.initMocks(this)(在JUnit 4中)或MockitoExtension(在JUnit 5中)来初始化这些注解。

使用示例

示例一:普通属性注入

这里以解析坐标为例,输入是地址,输出是坐标,坐标的解析需要依赖高德服务。

坐标解析类

/**  * 获取坐标服务,依赖高德地图获取坐标  */  
public class LocationService {  private GMapLocationService gMapLocationService = new GMapLocationService();  public String getLocation(String address) {  return gMapLocationService.getLocation(address);  }  
}

高德获取坐标服务类

public class GMapLocationService {  public String getLocation(String address) {  return "0,0";  }  
}

测试类

@InjectMocks标记的类表示这个类成员需要使用@Mock注解修饰的对象。

import org.junit.jupiter.api.Test;  
import org.junit.jupiter.api.extension.ExtendWith;  
import org.mockito.InjectMocks;  
import org.mockito.Mock;  
import org.mockito.junit.jupiter.MockitoExtension;  import static org.mockito.Mockito.when;  @ExtendWith(MockitoExtension.class)  
public class LocationServiceTest {  @Mock  private GMapLocationService gMapLocationService;  @InjectMocks  private LocationService locationService;  @Test  public void test(){  // 设置 mock 行为  when(gMapLocationService.getLocation("北京市通州区万达广场")).thenReturn("116.304642,39.978442");  // 调用方法  String location = locationService.getLocation("北京市通州区万达广场");  System.out.println(location);  }  
}
示例二:Spring Bean 对象注入

DemoTableService依赖DemoTableDao#selectAll方法。

@ExtendWith(MockitoExtension.class)  
public class MockDaoTest {  @Mock  private DemoTableDao demoTableDao;  @InjectMocks  private DemoTableService demoTableService;  @Test  public void test(){  // 创建示例数据  List<DemoTable> mockDatas = new ArrayList<>();  DemoTable demoTable = new DemoTable();  demoTable.setId(1L);  demoTable.setName("xiaoming");  demoTable.setAge(18);  mockDatas.add(demoTable);  // 模拟对象行为  when(demoTableDao.selectAll()).thenReturn(mockDatas);  // 方法调用  List<DemoTable> demoTables = demoTableService.selectAll();  System.out.println(demoTables);  }  
}

结语

使用Mockito我们可以:

  • 隔离测试: 在测试一个类时,使用Mockito来模拟该类的依赖对象,以便将测试的重点放在该类本身的逻辑上。

  • 依赖复杂性: 当依赖对象的创建或行为复杂时,通过模拟对象可以避免复杂的设置。

  • 边界条件测试: 模拟对象可以轻松地创建异常或边界条件,以测试代码的鲁棒性。

到这里,Mockito的基础用法就讲完了,其还有一些高级用法:

  • 验证行为: 使用verify()方法可以验证某个方法是否被调用,以及调用的次数。例如:
verify(mockedList).get(0);
verify(mockedList, times(1)).get(0);
  • 参数匹配: 通过anyInt()anyString()等参数匹配器,可以验证方法调用时的参数。例如:
when(mockedList.get(anyInt())).thenReturn("element");

可以自己尝试去探索啦!

以上,祝你今天愉快!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/17076.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java 字符编码与解码:深入理解 Charset 类

目录 引言 一、什么是字符集&#xff08;Charset&#xff09;&#xff1f; 二、Charset 类的核心功能 1. 获取字符集实例 2. 编码与解码 示例1&#xff1a;字符串转字节数组 示例2&#xff1a;处理不同字符集的乱码问题 3. 字符集检测与支持 三、Charset 类的常用方法…

Redis7.0八种数据结构底层原理

导读 本文介绍redis应用数据结构与物理存储结构,共八种应用数据结构和 一. 内部数据结构 1. sds sds是redis自己设计的字符串结构有以下特点: jemalloc内存管理预分配冗余空间二进制安全(c原生使用\0作为结尾标识,所以无法直接存储\0)动态计数类型(根据字符串长度动态选择…

本地Deepseek-r1:7b模型集成到Google网页中对话

本地Deepseek-r1:7b网页对话 基于上一篇本地部署的Deepseek-r1:7b&#xff0c;使用黑窗口对话不方便&#xff0c;现在将本地模型通过插件集成到Google浏览器中 安装Google插件 在Chrome应用商店中搜索page assis 直接添加至Chrome 修改一下语言 RAG设置本地运行的模型&#…

【设计模式】【行为型模式】观察者模式(Observer)

&#x1f44b;hi&#xff0c;我不是一名外包公司的员工&#xff0c;也不会偷吃茶水间的零食&#xff0c;我的梦想是能写高端CRUD &#x1f525; 2025本人正在沉淀中… 博客更新速度 &#x1f44d; 欢迎点赞、收藏、关注&#xff0c;跟上我的更新节奏 &#x1f3b5; 当你的天空突…

gitlab Webhook 配置jenkins时“触发远程构建 (例如,使用脚本)”报错

报错信息&#xff1a; <html> <head> <meta http-equiv"Content-Type" content"text/html;charsetISO-8859-1"/> <title>Error 403 No valid crumb was included in the request</title> </head> <body><h2…

AI赋能前端开发:薪资潜力无限的未来

在当今竞争激烈的就业市场&#xff0c;掌握AI写代码工具等AI技能已经成为许多专业人士提升竞争力的关键。尤其在快速发展的前端开发领域&#xff0c;AI的应用更是日新月异&#xff0c;为开发者带来了前所未有的机遇。高薪职位对熟练掌握AI技术的前端开发者的需求与日俱增&#…

外包干了4年,技术退步太明显了。。。。。

先说一下自己的情况&#xff0c;本科生生&#xff0c;20年通过校招进入武汉某软件公司&#xff0c;干了差不多4年的功能测试&#xff0c;今年国庆&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落!而我已经在一个企业干了四年的功能…

平面与平面相交算法杂谈

1.前言 空间平面方程&#xff1a; 空间两平面如果不平行&#xff0c;那么一定相交于一条空间直线&#xff0c; 空间平面求交有多种方法&#xff0c;本文进行相关讨论。 2.讨论 可以联立方程组求解&#xff0c;共有3个变量&#xff0c;2个方程&#xff0c;而所求直线有1个变量…

【状态空间方程】对于状态空间方程矩阵D≠0时的状态反馈与滑模控制

又到新的一年啦&#xff0c;2025新年快乐~。前几个月都没更新&#xff0c;主要还是因为不能把项目上的私密工作写进去&#xff0c;所以暂时没啥可写的。最近在山里实习&#xff0c;突然想起年前遗留了个问题一直没解决&#xff0c;没想到这两天在deepseek的加持下很快解决了&am…

LearningFlow:大语言模型城市驾驶的自动化策略学习工作流程

25年1月来自香港科技大学广州分校的论文“LearningFlow: Automated Policy Learning Workflow for Urban Driving with Large Language Models”。 强化学习 (RL) 的最新进展表明其在自动驾驶领域具有巨大潜力。尽管前景光明&#xff0c;但诸如手动设计奖励函数和复杂环境中的…

大语言模型多代理协作(MACNET)

大语言模型多代理协作(MACNET) Scaling Large-Language-Model-based Multi-Agent Collaboration 提出多智能体协作网络(MACNET),以探究多智能体协作中增加智能体数量是否存在类似神经缩放定律的规律。研究发现了小世界协作现象和协作缩放定律,为LLM系统资源预测和优化…

【OpenCV】双目相机计算深度图和点云

双目相机计算深度图的基本原理是通过两台相机从不同角度拍摄同一场景&#xff0c;然后利用视差来计算物体的距离。本文的Python实现示例&#xff0c;使用OpenCV库来处理图像和计算深度图。 1、数据集介绍 Mobile stereo datasets由Pan Guanghan、Sun Tiansheng、Toby Weed和D…

PT8032 3 通道触摸 IC

1. 概述 PT8032 是一款电容式触摸控制 ASIC &#xff0c;支持 3 通道触摸输入 ,2 线 BCD 码输出。具有低功耗、 高抗干扰、宽工作电压范围、高穿透力的突出优势。 2. 主要特性 工作电压范围&#xff1a; 2.4~5.5V 待机电流约 9uAV DD5V&CMOD10nF 3 通道触…

像指针操作、像函数操作的类

像指针一样的类。把一个类设计成像一个指针。什么操作符运用到指针上&#xff1f; 使用标准库的时候&#xff0c;里面有个很重要的东西叫容器。容器本身一定带着迭代器。迭代器作为另外一种智能指针。迭代器指向容器里的一个元素。迭代器用来遍历容器。 _list_iterator是链表迭…

Pikachu–XXE漏洞

Pikachu–XXE漏洞 一、XML基础概念 XML文档结构由XML声明&#xff0c;DTD(文档类型定义)&#xff0c;文档元素三部分构成&#xff01; #XML是可扩展标记语言(Extensible Markup Language),是设计用来进行数据的传输与存储。 #eg: <!--XML声明--><!--指明XML文档的版…

matlab-simulink

1、信号到对象解析指示符 代表的意义是&#xff1a;信号名称必须解析为信号对象 2、input inport 双击空白区域输入模块名字&#xff0c;自动联想显示相关模块 没看出太大的差别 3、Stateflow 双击空白区域输入stateflow、或者chart或者常用库里面去查找 4、离散时间积分…

简单几个步骤完成 Oracle 到金仓数据库(KingbaseES)的迁移目标

作为国产数据库的领军选手&#xff0c;金仓数据库&#xff08;KingbaseES&#xff09;凭借其成熟的技术架构和广泛的市场覆盖&#xff0c;在国内众多领域中扮演着至关重要的角色。无论是国家电网、金融行业&#xff0c;还是铁路、医疗等关键领域&#xff0c;金仓数据库都以其卓…

网络安全概论——网络安全基础

一、网络安全引言 信息安全的四个属性&#xff08;信息安全的基本目标 &#xff09; 保密性:信息不会被泄露给非授权用户完整性&#xff1a;保证数据的一致性可用性&#xff1a;合法用户不会被拒绝服务合法使用&#xff1a;不会被非授权用户或以非授权的方式使用 二、网络安全…

数据结构-链式二叉树

文章目录 一、链式二叉树1.1 链式二叉树的创建1.2 根、左子树、右子树1.3 二叉树的前中后序遍历1.3.1前(先)序遍历1.3.2中序遍历1.3.3后序遍历 1.4 二叉树的节点个数1.5 二叉树的叶子结点个数1.6 第K层节点个数1.7 二叉树的高度1.8 查找指定的值(val)1.9 二叉树的销毁 二、层序…

SpringCloud系列教程:微服务的未来(二十三)SpringAMQP快速入门、Work Queues、Fanout交换机

前言 Spring AMQP是Spring框架中用于与消息中间件&#xff08;如RabbitMQ&#xff09;进行交互的一个项目&#xff0c;它简化了消息发送、接收以及消息处理的过程。通过Spring AMQP&#xff0c;开发者可以快速实现基于RabbitMQ的消息传递系统。本文将介绍Spring AMQP的快速入门…