当前位置: 首页 > article >正文

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 对象注入到被测类中。

注入规则

  1. 构造器注入(优先):匹配参数类型和数量。
  2. Setter 注入:调用 setter 方法。
  3. 字段注入(最后):直接反射注入字段。

示例

@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. 最佳实践
  1. 保持测试简洁:使用注解减少手动初始化代码。
  2. 明确依赖关系:通过 @InjectMocks 明确被测类的依赖注入方式。
  3. 避免过度 Mock:仅 Mock 外部依赖,保留核心逻辑的真实性。
  4. 结合 AssertJ:使用流式断言提高测试可读性:
    assertThat(capturedEmail.getSubject()).contains("Welcome");
    

通过合理使用 Mockito 注解,可以显著提升单元测试的编写效率和可维护性。

相关文章:

2.5 使用注解进行单元测试详解

Mockito 使用注解进行单元测试详解 Mockito 提供了一系列注解来简化测试代码的编写&#xff0c;减少手动创建和管理 Mock 对象的样板代码。结合 JUnit 5&#xff0c;可以更高效地构建清晰、易维护的单元测试。 1. 核心注解概览 注解作用Mock创建并注入一个 Mock 对象&#xf…...

2025年SEO工具有哪些?老品牌SEO工具有哪些

随着2025年互联网的发展和企业线上营销的日益重要&#xff0c;SEO&#xff08;搜索引擎优化&#xff09;逐渐成为了提高网站曝光率和流量的重要手段。SEO的工作不仅仅是简单地通过关键词优化和内容发布就能够实现的&#xff0c;它需要依赖一系列专业的SEO工具来帮助分析、监测和…...

使用 React 16+Webpack 和 pdfjs-dist 或 react-pdf 实现 PDF 文件显示、定位和高亮

写在前面 在本文中&#xff0c;我们将探讨如何使用 React 16Webpack 和 pdfjs-dist 或 react-pdf 库来实现 PDF 文件的显示、定位和高亮功能。这些库提供了强大的工具和 API&#xff0c;使得在 Web 应用中处理 PDF 文件变得更加容易。 项目设置 首先&#xff0c;我们需要创建…...

LabVIEW显微镜成像偏差校准

在高精度显微镜成像中&#xff0c;用户常常需要通过点击图像的不同位置&#xff0c;让电机驱动探针移动到指定点进行观察。然而&#xff0c;在实际操作中&#xff0c;经常会遇到一个问题&#xff1a;当点击位于图像中心附近的点时&#xff0c;探针能够相对准确地定位&#xff1…...

【Elasticsearch】文本分析Text analysis概述

文本分析概述 文本分析使 Elasticsearch 能够执行全文搜索&#xff0c;搜索结果会返回所有相关的结果&#xff0c;而不仅仅是完全匹配的结果。 如果你搜索“Quick fox jumps”&#xff0c;你可能希望找到包含“A quick brown fox jumps over the lazy dog”的文档&#xff0c…...

23页PDF | 国标《GB/T 44109-2024 信息技术 大数据 数据治理实施指南 》发布

一、前言 《信息技术 大数据 数据治理实施指南》是中国国家标准化管理委员会发布的关于大数据环境下数据治理实施的指导性文件&#xff0c;旨在为组织开展数据治理工作提供系统性的方法和框架。报告详细阐述了数据治理的实施过程&#xff0c;包括规划、执行、评价和改进四个阶…...

AI代码生成器如何重塑前端开发的工作环境

近年来&#xff0c;人工智能&#xff08;AI&#xff09;技术迅猛发展&#xff0c;深刻地改变着各行各业的工作方式。在软件开发领域&#xff0c;AI写代码工具的出现更是掀起了一场革命&#xff0c;尤其对前端开发工程师的工作环境和协作方式产生了深远的影响。本文将深入探讨AI…...

kafka的架构和工作原理

目录 Kafka 架构 Kafka 工作原理 Kafka 数据流 Kafka 核心特性 总结 Kafka 架构 1. 生产者(Producer) 2. 消费者(Consumer) 3. 主题(Topic) 4. 分区(Partition) 5. 副本(Replica) 6. 代理(Broker) 7. ZooKeeper(旧版本)/KRaft(新版本) Kafka 工作…...

Xcode证书密钥导入

证书干嘛用 渠道定期会给xcode证书&#xff0c;用来给ios打包用&#xff0c;证书里面有记录哪些设备可以打包进去。 怎么换证书 先更新密钥 在钥匙串访问中&#xff0c;选择系统。(选登录也行&#xff0c;反正两个都要导入就是了)。 mac中双击所有 .p12 后缀的密钥&#xff…...

索引的详细介绍

数据库索引是一种用于加速数据检索的数据结构&#xff0c;类似于书籍的目录。通过索引&#xff0c;数据库可以快速定位数据&#xff0c;而无需扫描整个表。以下是关于数据库索引的详细介绍&#xff1a; 1. 索引的基本概念 定义&#xff1a;索引是数据库表中一列或多列的值及其…...

Python 基于 OpenCV 的人脸识别上课考勤系统(附源码,部署教程)

博主介绍&#xff1a;✌2013crazy、10年大厂程序员经历。全网粉丝12W、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;&a…...

TikTok网页版访问受限?一文解析解决方案

TikTok网页版是许多用户用来浏览视频、管理账号和发布内容的重要工具。然而&#xff0c;部分用户可能会遇到无法打开TikTok网页版的问题&#xff0c;如页面加载失败、显示网络错误或提示访问受限。本文将帮助你快速排查问题&#xff0c;并提供解决方案&#xff0c;让你顺利访问…...

本地部署【LLM-deepseek】大模型 ollama+deepseek/conda(python)+openwebui/docker+openwebui

通过ollama本地部署deepseek 总共两步 1.模型部署 2.[web页面] 参考官网 ollama:模型部署 https://ollama.com/ open-webui:web页面 https://github.com/open-webui/open-webui 设备参考 Mac M 芯片 windows未知 蒸馏模型版本:deepseek-r1:14b 运行情况macminim2 24256 本地…...

【vs2022配置cursor】

Cursor搭配cmake实现C程序的编译、运行和调试的参考地址 cursor下载地址 第一步&#xff1a; 电脑上按爪cmake 第二步&#xff1a;cursor 配置 安装中文 第三步环境变量&#xff1a; D:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.35.322…...

Redis 的缓存雪崩、缓存穿透和缓存击穿详解,并提供多种解决方案

本文是对 Redis 知识的补充&#xff0c;在了解了如何搭建多种类型的 Redis 集群&#xff0c;并清楚了 Redis 集群搭建的过程的原理和注意事项之后&#xff0c;就要开始了解在使用 Redis 时可能出现的突发问题和对应的解决方案。 引言&#xff1a;虽然 Redis 是单线程的&#xf…...

Docker使用指南与Dockerfile文件详解:从入门到实战

Docker使用指南与Dockerfile文件详解:从入门到实战 文章目录 **Docker使用指南与Dockerfile文件详解:从入门到实战****引言****第一部分:Docker 核心概念速览****1. Docker 基础架构****2. Docker 核心命令****第二部分:Dockerfile 文件深度解析****1. Dockerfile 是什么?…...

如何在个人电脑本地化部署Deepseek-R1大模型

文章目录 Deepseek概述公司简介DeepSeek模型优势DeepSeek模型发展历史Ollama安装Deepseek版本选择Deepseek支持的客户端工具编程语言客户端库桌面客户端插件类其他工具客户端工具配置cherryStudio配置测试如何使用DeepSeek满血版什么是 DeepSeek R1 满血版?deepseek官方第三方…...

DeepSeek-R1复现方案梳理

open-r1 项目地址&#xff1a;https://github.com/huggingface/open-r1 由huggingface组建&#xff0c;目前刚上线2周&#xff0c;发布了最新进展open-r1/update-1&#xff0c;在MATH-500任务上接近deepseek的指标&#xff0c;可以在open-r1/open-r1-eval-leaderboard查看指标的…...

【Redis】 - Redis的Bitmap实现用户签到

Redis的Bitmap实现用户签到 使用Redis的Bitmap数据结构来记录用户的每日签到状态是一种高效且节省空间的方法。通过将用户ID和日期结合生成动态Key&#xff0c;可以轻松管理不同用户在不同日期的签到情况。下面详细介绍如何设计这一方案。 设计思路 动态Key生成&#xff1a;根…...

用php tp6对接钉钉审批流的 table 表格 明细控件 旧版sdk

核心代码 foreach ($flows[product_list] as $k>$gift) {$items_list[] [[name > 商品名称, value > $gift[product_name] ?? ],[name > 规格, value > $gift[product_name] ?? ],[name > 数量, value > $gift[quantity] ?? ],[name > 单位, v…...

使用DeepSeek建立一个智能聊天机器人0.07

进一步完善获取API密钥和DeepSeek的API端点&#xff0c;我们可以添加更多的错误处理和默认值设置&#xff0c;确保程序在各种情况下都能正常运行。同时&#xff0c;我们还可以提供一个更友好的用户界面&#xff0c;以便用户可以轻松地设置和查看配置信息。 以下是进一步完善的…...

PySpark查找Dataframe中的非ASCII字符并导出Excel文件

from pyspark.sql import SparkSession from pyspark.sql.types import StringType from pyspark.sql.functions import udf, col from pyspark.sql.types import BooleanType import pandas as pd# 初始化Spark会话 spark SparkSession.builder.appName("StringFilter&q…...

大模型RLHF:PPO原理与源码解读

大模型RLHF&#xff1a;PPO原理与源码解读 原文链接&#xff1a;图解大模型RLHF系列之&#xff1a;人人都能看懂的PPO原理与源码解读 本文直接从一个RLHF开源项目源码入手&#xff08;deepspeed-chat&#xff09;&#xff0c;根据源码的实现细节&#xff0c;给出尽可能丰富的训…...

SQLite 数据库:优点、语法与快速入门指南

文章目录 一、引言二、SQLite 的优点 &#x1f4af;三、SQLite 的基本语法3.1 创建数据库3.2 创建表3.3 插入数据3.4 查询数据3.5 更新数据3.6 删除数据3.7 删除表 四、快速入门指南4.1 安装 SQLite4.2 创建数据库4.3 创建表4.4 插入数据4.5 查询数据4.6 更新数据4.7 删除数据4…...

pytorch笔记:mm VS bmm

1 bmm (batch matrix multiplication) 批量矩阵乘法&#xff0c;用于同时处理多个矩阵的乘法bmm 的输入是两个 3D 张量&#xff08;batch of matrices&#xff09;&#xff0c;形状分别为 (batch_size, n, m) 和 (batch_size, m, p)bmm 输出的形状是 (batch_size, n, p) 2 mm…...

5、大模型的记忆与缓存

文章目录 本节内容介绍记忆Mem0使用 mem0 实现长期记忆 缓存LangChain 中的缓存语义缓存 本节内容介绍 本节主要介绍大模型的缓存思路&#xff0c;通过使用常见的缓存技术&#xff0c;降低大模型的回复速度&#xff0c;下面介绍的是使用redis和mem0&#xff0c;当然redis的语义…...

LangChain系列:LangChain基础入门教程

LangChain 是一个开源框架&#xff0c;旨在简化使用大型语言模型&#xff08;LLM&#xff09;创建应用程序的过程。它为链提供了标准接口&#xff0c;与许多其他工具进行了集成&#xff0c;并为常见应用提供了端到端的链。 LangChain 让 AI 开发人员能够基于大型语言模型&#…...

修改docker内容器中的某配置文件的命令

先找到配置文件config.php find / -name "config.php" 2>/dev/null 然后用vi编辑器修改配置文件 vi /var/www/config.php 最后就是vi的基本操作&#xff0c;根据具体需求使用&#xff1a; vi 有两种主要模式&#xff1a; 命令模式&#xff1a;进入 vi 后的默认…...

无人机遥感图像拼接及处理实践技术:生态环境监测、农业、林业等领域,结合图像拼接与处理技术,能够帮助我们更高效地进行地表空间要素的动态监测与分析

近年来&#xff0c;无人机技术在遥感领域的应用越来越广泛&#xff0c;尤其是在生态环境监测、农业、林业等领域&#xff0c;无人机遥感图像的处理与分析成为了科研和业务化工作中的重要环节。通过无人机获取的高分辨率影像数据&#xff0c;结合图像拼接与处理技术&#xff0c;…...

基于Springmvc+MyBatis+Spring+Bootstrap+EasyUI+Mysql的个人博客系统

基于SpringmvcMyBatisSpringBootstrapEasyUIMysql的个人博客系统 1.项目介绍 使用Maven3Spring4SpringmvcMybatis3架构&#xff1b;数据库使用Mysql&#xff0c;数据库连接池使用阿里巴巴的Druid&#xff1b;使用Bootstrap3 UI框架实现博客的分页显示&#xff0c;博客分类&am…...