2.5 使用注解进行单元测试详解
Mockito 使用注解进行单元测试详解
Mockito 提供了一系列注解来简化测试代码的编写,减少手动创建和管理 Mock 对象的样板代码。结合 JUnit 5,可以更高效地构建清晰、易维护的单元测试。
1. 核心注解概览
| 注解 | 作用 |
|---|---|
@Mock | 创建并注入一个 Mock 对象(完全模拟,方法默认返回空或默认值)。 |
@Spy | 创建并注入一个 Spy 对象(部分模拟,默认调用真实方法,除非显式覆盖)。 |
@InjectMocks | 自动将 @Mock 或 @Spy 对象注入到被测类中(依赖注入)。 |
@Captor | 自动初始化 ArgumentCaptor,用于捕获方法参数。 |
@ExtendWith | 启用 Mockito 扩展(JUnit 5 必需),替代旧版 @RunWith。 |
2. 注解配置与启用
2.1 启用 Mockito 支持
在测试类上添加 @ExtendWith(MockitoExtension.class),激活 Mockito 注解功能:
@ExtendWith(MockitoExtension.class) // JUnit 5 必加
public class UserServiceTest {// 测试代码...
}
2.2 自动初始化注解
无需手动调用 MockitoAnnotations.openMocks(this),@ExtendWith 已自动处理。
3. 注解使用详解
3.1 @Mock 注解
作用:创建完全模拟的依赖对象。
示例场景:
public class UserService {private final UserDao userDao;public UserService(UserDao userDao) {this.userDao = userDao;}public User getUserById(int id) {return userDao.findById(id);}
}
测试代码:
@ExtendWith(MockitoExtension.class)
class UserServiceTest {@Mockprivate UserDao mockUserDao; // 自动创建 Mock 对象@InjectMocksprivate UserService userService; // 自动注入 mockUserDao@Testvoid getUserById_ShouldReturnUser() {// 配置 Mock 行为when(mockUserDao.findById(1)).thenReturn(new User(1, "Alice"));// 调用被测方法User user = userService.getUserById(1);// 验证结果assertEquals("Alice", user.getName());verify(mockUserDao).findById(1);}
}
3.2 @Spy 注解
作用:创建部分模拟对象,保留真实方法逻辑,除非显式覆盖。
示例场景:
public class PaymentService {public boolean validateCard(String cardNumber) {return cardNumber != null && cardNumber.length() == 16;}public boolean processPayment(String cardNumber) {if (!validateCard(cardNumber)) return false;// 真实支付逻辑...return true;}
}
测试代码:
@ExtendWith(MockitoExtension.class)
class PaymentServiceTest {@Spy // 部分模拟,保留真实方法private PaymentService spyPaymentService;@Testvoid processPayment_ShouldUseMockedValidation() {// 覆盖 validateCard 方法doReturn(true).when(spyPaymentService).validateCard(anyString());// 调用被测方法(processPayment 会调用被覆盖的 validateCard)boolean result = spyPaymentService.processPayment("invalid_card");assertTrue(result);verify(spyPaymentService).validateCard("invalid_card");}
}
3.3 @InjectMocks 注解
作用:自动将 @Mock 或 @Spy 对象注入到被测类中。
注入规则:
- 构造器注入(优先):匹配参数类型和数量。
- Setter 注入:调用 setter 方法。
- 字段注入(最后):直接反射注入字段。
示例:
@ExtendWith(MockitoExtension.class)
class OrderServiceTest {@Mockprivate InventoryService inventoryService;@Mockprivate PaymentService paymentService;@InjectMocks // 自动注入 inventoryService 和 paymentServiceprivate OrderService orderService;@Testvoid placeOrder_ShouldCheckInventory() {when(inventoryService.checkStock(anyString())).thenReturn(true);orderService.placeOrder("product_123");verify(inventoryService).checkStock("product_123");}
}
3.4 @Captor 注解
作用:自动创建参数捕获器,简化参数验证。
示例:
@ExtendWith(MockitoExtension.class)
class NotificationServiceTest {@Mockprivate EmailClient mockEmailClient;@InjectMocksprivate NotificationService notificationService;@Captor // 自动初始化 ArgumentCaptorprivate ArgumentCaptor<EmailRequest> emailCaptor;@Testvoid sendWelcomeEmail_ShouldCaptureEmailContent() {notificationService.sendWelcomeEmail("user@example.com");verify(mockEmailClient).send(emailCaptor.capture());EmailRequest captured = emailCaptor.getValue();assertEquals("user@example.com", captured.getTo());assertTrue(captured.getSubject().contains("Welcome"));}
}
4. 常见问题与解决方案
| 问题 | 解决方案 |
|---|---|
@Mock 对象为 null | 检查是否添加 @ExtendWith(MockitoExtension.class)。 |
| 依赖注入失败 | 确保 @InjectMocks 类的依赖项有对应的 @Mock 或 @Spy 对象。 |
| Spy 对象调用真实方法导致异常 | 使用 doReturn().when() 替代 when().thenReturn() 避免执行真实方法。 |
| 参数捕获器未初始化 | 使用 @Captor 替代手动创建 ArgumentCaptor。 |
5. 高级整合:与 Spring Boot 测试结合
在 Spring Boot 测试中,可使用 @MockBean 替换容器中的 Bean:
@SpringBootTest
public class ProductServiceIntegrationTest {@MockBean // Spring 管理的 Mockprivate InventoryService mockInventoryService;@Autowiredprivate ProductService productService;@Testvoid reserveProduct_ShouldUseMockInventory() {when(mockInventoryService.reserve(anyString())).thenReturn(true);boolean result = productService.reserveProduct("product_123");assertTrue(result);}
}
6. 最佳实践
- 保持测试简洁:使用注解减少手动初始化代码。
- 明确依赖关系:通过
@InjectMocks明确被测类的依赖注入方式。 - 避免过度 Mock:仅 Mock 外部依赖,保留核心逻辑的真实性。
- 结合 AssertJ:使用流式断言提高测试可读性:
assertThat(capturedEmail.getSubject()).contains("Welcome");
通过合理使用 Mockito 注解,可以显著提升单元测试的编写效率和可维护性。
相关文章:
2.5 使用注解进行单元测试详解
Mockito 使用注解进行单元测试详解 Mockito 提供了一系列注解来简化测试代码的编写,减少手动创建和管理 Mock 对象的样板代码。结合 JUnit 5,可以更高效地构建清晰、易维护的单元测试。 1. 核心注解概览 注解作用Mock创建并注入一个 Mock 对象…...
当没有OpenGL时,Skia如何绘制?
Skia 是可以在没有 OpenGL 的情况下进行图形绘制的,但是具体能否成功绘制图形,取决于 Skia 是如何配置的,以及平台上是否提供了其他的底层图形 API。 Skia 的底层依赖 Skia 的目标是提供一种跨平台的 2D 图形绘制接口。为了加速图形渲染&…...
SaaS+AI应用架构:业务场景、智能体、大模型、知识库、传统工具系统
SaaSAI应用架构:业务场景、智能体、大模型、知识库、传统工具系统 大家好,我是汤师爷~ 在SaaS与AI应用的演进过程中,合理的架构设计至关重要。本节将详细介绍其五个核心层次: 业务场景层:发现和确定业务场景智能体层…...
Go 语言中如何高效地处理集合
文章精选推荐 1 JetBrains Ai assistant 编程工具让你的工作效率翻倍 2 Extra Icons:JetBrains IDE的图标增强神器 3 IDEA插件推荐-SequenceDiagram,自动生成时序图 4 BashSupport Pro 这个ides插件主要是用来干嘛的 ? 5 IDEA必装的插件&…...
布隆过滤器到底是什么东西?它有什么用
布隆过滤器:用概率换空间的奇妙数据结构 引言:当空间成为奢侈品 在互联网每天产生2.5万亿字节数据的时代,Google每秒处理超过9万次搜索请求,Redis缓存系统支撑着百万级QPS的访问。面对如此海量的数据处理需求,传统的…...
【数据结构初阶第十节】队列(详解+附源码)
好久不见。。。别不开心了,听听喜欢的歌吧 必须有为成功付出代价的决心,然后想办法付出这个代价。云边有个稻草人-CSDN博客 目录 一、概念和结构 二、队列的实现 Queue.h Queue.c test.c Relaxing Time! ————————————《有没…...
沪深300股指期权能对股指期货进行完全套保吗?
锦鲤三三每日分享期权知识,帮助期权新手及时有效地掌握即市趋势与新资讯! 沪深300股指期权能对股指期货进行完全套保吗? 沪深300股指期权是以沪深300指数为标的物的期权,而沪深300股指期货则是以该指数作为标的的期货合约。 理…...
JAVA学习第三天
继承关系变量访问的特点 01.方法中找 02.子类变量定义中找 03.父类中找 this和super关键字的使用区别: super父类构造函数的使用: 使用子类构造函数时,都会初始化父类的数据,自动调用父类的无参构造函数 super内存图——007 继…...
win11电脑其他WiFi可以连,只有一个WiFi连不上
这个问题卡了一小会,查了一些资料 后面发现 点击“诊断网络问题” 显示没有响应 第一步 重启wlan网络适配器 解决!!! 重新连接那个有问题的wifi,丝滑连接!...
leetcode_1760 袋子里最少数目的球
1. 题意 给定一个数组,和一个最多次操作次数。每次操作可以将数组中的一个数 x x x分成两个数 t x − t t\quad x-t tx−t。问 m a x O p e r a t i o n C n t maxOperationCnt maxOperationCnt次操作后,数组中最大的数最小的值是多少。 2. 题解 这个…...
Python 面向对象的三大特征
前言:本篇讲解面向对象的三大特征(封装,继承,多态),还有比较细致的(类属性类方法,静态方法),分步骤讲解,比较适合理清楚三大特征的思路 面向对象的…...
Linux下的进程切换与调度
目录 1.进程的优先级 优先级是什么 Linux下优先级的具体做法 优先级的调整为什么要受限 2.Linux下的进程切换 3.Linux下进程的调度 1.进程的优先级 我们在使用计算机的时候,通常会启动多个程序,这些程序最后都会变成进程,但是我们的硬…...
面向对象程序设计-实验六
7-1 函数重载(数据类型不同) 代码清单: #include<iostream> using namespace std; class axxx { public: void px(int n,int a[]) { for(int i0;i<n;i) { for(int j0;j<n-i-1;j) { int t; if(a[j]>a[j1]) { ta[j]; a[j…...
MongoDB 7 分片副本集升级方案详解(上)
#作者:任少近 文章目录 前言:Mongodb版本升级升级步骤环境1.1环境准备1.2standalone升级1.3分片、副本集升级 前言:Mongodb版本升级 在开始升级之前,请参阅 MongoDB下个版本中的兼容性变更文档,以确保您的应用程序和…...
【工业安全】-CVE-2022-35555- Tenda W6路由器 命令注入漏洞
文章目录 1.漏洞描述 2.环境搭建 3.漏洞复现 4.漏洞分析 4.1:代码分析 4.2:流量分析 5.poc代码: 1.漏洞描述 漏洞编号:CVE-2022-35555 漏洞名称:Tenda W6 命令注入 威胁等级:高危 漏洞详情࿱…...
算法分析 ——《模拟》
文章目录 《替换所有的问号》题目描述:代码演示:代码解析: 《提莫攻击》题目描述:代码演示:代码解析: [《Z 字形变换》](https://leetcode.cn/problems/zigzag-conversion/)题目描述:代码演示&a…...
将Sqlite3数据库挂在内存上处理
创作灵感:最近把小学生的口算题从2位数改到3位数,100以内四则运算练习(千纬数学)再次更新,选取难题-CSDN博客要不断刷题目,以前100以内的加减乘除也是这样刷出来的,代码如下: impor…...
前端大屏适配方案:从设计到实现的全流程指南
引言 随着数据可视化需求的增长,大屏展示项目在前端开发中越来越常见。然而,大屏开发面临独特的挑战: 屏幕分辨率多样:从1080P到4K甚至8K,如何保证清晰度?布局复杂:多图表、多组件如何合理排列…...
学习总结三十二
map #include<iostream> #include<map> using namespace std;int main() {//首先创建一个map对象map<int, char>oneMap;//插入数据oneMap.insert(pair<int, char>(1, A));oneMap.insert(make_pair(2,B));oneMap.insert(map<int,char>::value_ty…...
飞书专栏-TEE文档
CSDN学院课程连接:https://edu.csdn.net/course/detail/39573...
构建个人技能库:从代码片段到可复用技能单元的设计与实践
1. 项目概述:当代码遇上魔法,技能库的构建哲学在软件开发的日常里,我们常常会羡慕那些“魔法师”般的同事:他们似乎总能信手拈来一段代码,优雅地解决一个棘手问题;或者拥有一个私人的“百宝箱”,…...
渗透PHP伪协议
一、debug调试 1、定义 Debug,又叫断点调试,就是对写好的程序进行逐步运行、分解、调试的过程,通过这个过程,我们可以跟踪程序的详细运行过程, 是程序员的开发神器,也是开发必会的一个重要技能。 2、意义…...
大模型风口已至:月薪30K+的AI Agent开发岗,你准备好了吗?
文章介绍了如何借助不同版本的Agents实现智能自动化,并详细描述了AI应用工程师和大模型算法工程师的岗位职责和任职要求。文章还强调了AI学习的重要性,指出最先掌握AI的人将具有竞争优势,并提供了大模型AI学习和面试资料,帮助读者…...
多渠道订单数据处理自动化,落地步骤与ERP打通方案 | 2026企业级智能体实战手册
在2026年的数字化转型深水区,企业面临的不再是“是否要自动化”的问题, 而是如何在高并发、多维度的全渠道业务压力下, 实现订单流、资金流与信息流的绝对同步。 传统的OMS(订单管理系统)与ERP(企业资源计划…...
如何快速掌握京东自动评价工具:面向新手的完整指南
如何快速掌握京东自动评价工具:面向新手的完整指南 【免费下载链接】jd_AutoComment 自动评价,仅供交流学习之用 项目地址: https://gitcode.com/gh_mirrors/jd/jd_AutoComment 在快节奏的电商购物时代,你是否也曾为堆积如山的待评价订单而烦恼&a…...
【2026实测】论文AI率从81%降至个位数?8款降AIGC工具深度横测
内容ai率检测数值太高,不得不熬夜改了一遍又一遍,润色到想吐,结果检测报告上数字还是不尽人意,截止日期越逼越近,真的是没办法了。 我花了整整三天,把2026全网热门的几十款降AI工具通通测了个遍࿰…...
别再Ctrl+F GitHub了!Perplexity高级提示词工程(含18个已验证模板),让开源检索进入“所想即所得”时代
更多请点击: https://intelliparadigm.com 第一章:Perplexity GitHub资源检索的范式革命 从关键词匹配到语义理解的跃迁 传统 GitHub 搜索依赖精确的仓库名、文件路径或正则表达式,而 Perplexity 引入的 LLM 驱动检索将自然语言查询&#x…...
Sketch Find and Replace终极指南:设计师必备的批量文本替换神器
Sketch Find and Replace终极指南:设计师必备的批量文本替换神器 【免费下载链接】Sketch-Find-And-Replace Sketch plugin to do a find and replace on text within layers 项目地址: https://gitcode.com/gh_mirrors/sk/Sketch-Find-And-Replace 还在为Sk…...
如何快速掌握ComfyUI-WanVideoWrapper:AI视频生成从入门到精通
如何快速掌握ComfyUI-WanVideoWrapper:AI视频生成从入门到精通 【免费下载链接】ComfyUI-WanVideoWrapper 项目地址: https://gitcode.com/GitHub_Trending/co/ComfyUI-WanVideoWrapper ComfyUI-WanVideoWrapper 是一款专为ComfyUI设计的强大AI视频生成插件…...
FPGA生成SPWM的另一种思路:抛弃ROM,用DDS IP核与CORDIC算法实时生成正弦波
FPGA实时生成SPWM:基于DDS IP核与CORDIC算法的高效实现方案 在电力电子和电机控制领域,SPWM(正弦脉宽调制)技术因其优异的谐波特性和高效率而广受青睐。传统FPGA实现方案通常采用预存波形数据的ROM方法,虽然实现简单&a…...
