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

JUnit​​ 和 ​​Mockito​​ 的详细说明及示例,涵盖核心概念、常用注解、测试场景和实战案例。

一、JUnit 详解

1. JUnit 核心概念

  • ​测试类​​:以 Test 结尾的类(或通过 @Test 注解标记的方法)。
  • ​断言(Assertions)​​:验证预期结果与实际结果是否一致(如 assertEquals())。
  • ​测试生命周期​​:通过注解管理测试的初始化和清理(如 @BeforeEach@AfterEach)。
  • ​参数化测试​​:针对多组输入数据运行同一测试逻辑(JUnit 5+)。

2. JUnit 5 示例

(1) 基础测试
java
复制
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;class CalculatorTest {@Testvoid testAdd() {Calculator calculator = new Calculator();assertEquals(5, calculator.add(2, 3), "2+3 应等于 5");}@Testvoid testDivideByZero() {Calculator calculator = new Calculator();assertThrows(ArithmeticException.class, () -> calculator.divide(10, 0));}
}
(2) 生命周期管理
java
复制
import org.junit.jupiter.api.*;class LifecycleTest {@BeforeEachvoid setup() {System.out.println("每个测试方法执行前运行");}@AfterEachvoid teardown() {System.out.println("每个测试方法执行后运行");}@Testvoid test1() {System.out.println("运行测试1");}@Testvoid test2() {System.out.println("运行测试2");}
}
(3) 参数化测试
java
复制
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;class ParameterizedTest {@ParameterizedTest@CsvSource({"2, 3, 5", "5, 7, 12", "-1, 1, 0"})void testAdd(int a, int b, int expected) {Calculator calculator = new Calculator();assertEquals(expected, calculator.add(a, b));}
}

二、Mockito 详解

1. Mockito 核心概念

  • ​模拟对象(Mock)​​:通过 @Mock 或 mock() 创建,隔离外部依赖。
  • ​注入依赖​​:使用 @InjectMocks 自动注入模拟对象到被测类。
  • ​验证行为​​:通过 verify() 检查方法是否按预期调用。
  • ​定义返回值​​:使用 when().thenReturn() 模拟方法行为。

2. Mockito 示例

(1) 基础模拟
java
复制
import static org.mockito.Mockito.*;
import org.junit.jupiter.api.Test;// 被测类
class UserService {private UserRepository userRepository;public UserService(UserRepository userRepository) {this.userRepository = userRepository;}public User getUserById(int id) {return userRepository.findById(id);}
}// 模拟依赖
interface UserRepository {User findById(int id);
}class UserServiceTest {@Testvoid testGetUserById() {// 1. 创建模拟对象UserRepository mockUserRepository = mock(UserRepository.class);// 2. 定义模拟行为when(mockUserRepository.findById(1)).thenReturn(new User(1, "Alice"));// 3. 注入模拟对象到被测类UserService userService = new UserService(mockUserRepository);// 4. 执行测试User user = userService.getUserById(1);// 5. 验证结果assertEquals("Alice", user.getName());verify(mockUserRepository).findById(1); // 确认方法被调用}
}
(2) 验证调用次数
java
复制
@Test
void testSaveUser() {UserRepository mockUserRepository = mock(UserRepository.class);UserService userService = new UserService(mockUserRepository);userService.saveUser(new User(2, "Bob"));userService.saveUser(new User(3, "Charlie"));// 验证 save 方法被调用了两次verify(mockUserRepository, times(2)).save(any(User.class));
}
(3) 模拟异常场景
java
复制
@Test
void testUserNotFound() {UserRepository mockUserRepository = mock(UserRepository.class);UserService userService = new UserService(mockUserRepository);when(mockUserRepository.findById(99)).thenThrow(new RuntimeException("User not found"));assertThrows(RuntimeException.class, () -> userService.getUserById(99));
}

三、Mockito 高级用法

1. Spy 对象

  • ​部分模拟​​:真实对象的部分方法被监控,其余方法正常执行。
java
复制
@Test
void testSpy() {List<String> list = new ArrayList<>();List<String> spyList = spy(list);doNothing().when(spyList).clear(); // 监控 clear() 方法spyList.add("test");verify(spyList).add("test"); // 验证 add() 被调用spyList.clear(); // 实际调用真实方法
}

2. ArgumentCaptor 捕获参数

  • ​捕获方法参数​​:验证方法调用时传入的参数。
java
复制
@Test
void testCaptureArgument() {UserRepository mockUserRepository = mock(UserRepository.class);UserService userService = new UserService(mockUserRepository);userService.saveUser(new User(4, "David"));ArgumentCaptor<User> userCaptor = ArgumentCaptor.forClass(User.class);verify(mockUserRepository).save(userCaptor.capture());User capturedUser = userCaptor.getValue();assertEquals(4, capturedUser.getId());
}

四、JUnit 与 Mockito 结合实战

场景:测试订单服务(依赖数据库和外部 API)

java
复制
// 被测类
class OrderService {private OrderRepository orderRepository;private PaymentGateway paymentGateway;public OrderService(OrderRepository orderRepository, PaymentGateway paymentGateway) {this.orderRepository = orderRepository;this.paymentGateway = paymentGateway;}public Order createOrder(OrderRequest request) {// 1. 保存订单到数据库Order order = orderRepository.save(request.toOrder());// 2. 调用支付网关paymentGateway.charge(order.getId(), order.getAmount());return order;}
}// 测试类
class OrderServiceTest {@Testvoid testCreateOrder() {// 1. 模拟依赖OrderRepository mockRepo = mock(OrderRepository.class);PaymentGateway mockGateway = mock(PaymentGateway.class);// 2. 定义模拟行为when(mockRepo.save(any(Order.class))).thenAnswer(invocation -> invocation.getArgument(0));doNothing().when(mockGateway).charge(anyInt(), anyDouble());// 3. 注入依赖并测试OrderService orderService = new OrderService(mockRepo, mockGateway);OrderRequest request = new OrderRequest(1001, 99.9);Order order = orderService.createOrder(request);// 4. 验证流程verify(mockRepo).save(argThat(o -> o.getUserId() == 1001));verify(mockGateway).charge(order.getId(), 99.9);}
}

五、常见问题与解决

1. ​​Mockito 无法模拟静态方法(JUnit 5)​

  • ​原因​​:Mockito 默认不支持静态方法模拟。
  • ​解决​​:使用 mockito-inline 库并启用静态模拟:
    java
    复制
    @ExtendWith(MockitoExtension.class)
    class MyTest {@Testvoid testStaticMethod() {try (MockedStatic<StaticClass> mocked = mockStatic(StaticClass.class)) {mocked.when(StaticClass.staticMethod()).thenReturn("mocked");// 执行测试...}}
    }

2. ​​测试覆盖率低​

  • ​工具​​:使用 JaCoCo 或 Cobertura 生成覆盖率报告。
  • ​优化​​:确保测试覆盖正常路径、边界条件和异常场景。

六、总结

  • ​JUnit​​:核心是编写可重复的自动化测试,通过断言验证逻辑正确性。
  • ​Mockito​​:通过模拟依赖隔离被测对象,支持复杂场景的单元测试。
  • ​最佳实践​​:
    • 测试粒度小,聚焦单一功能。
    • 使用 @BeforeEach 初始化测试环境。
    • 避免过度模拟,优先测试真实逻辑。

​应用场景​​:

  • ​JUnit​​:所有单元测试的基础框架。
  • ​Mockito​​:依赖外部服务或复杂对象的场景(如数据库、API 调用)。

相关文章:

JUnit​​ 和 ​​Mockito​​ 的详细说明及示例,涵盖核心概念、常用注解、测试场景和实战案例。

一、JUnit 详解 1. JUnit 核心概念 ​​测试类​​&#xff1a;以 Test 结尾的类&#xff08;或通过 Test 注解标记的方法&#xff09;。​​断言&#xff08;Assertions&#xff09;​​&#xff1a;验证预期结果与实际结果是否一致&#xff08;如 assertEquals()&#xff0…...

【Go语言基础【7】】条件语句

文章目录 零、概述一、if 条件语句1. 单条件模型2. 多条件模型&#xff08;else if&#xff09;3. 条件嵌套与优化 二、switch 条件判断1. 基本用法2. fallthrough 穿透执行3. break 终止执行 零、概述 语句类型适用场景核心特点if-else单条件或简单多条件判断逻辑清晰&#x…...

【Python 算法零基础 4.排序 ⑪ 十大排序算法总结】

目录 一、选择排序回顾 二、冒泡排序回顾 三、插入排序回顾 四、计数排序回顾 五、归并排序回顾 六、快速排序回顾 七、桶排序回顾 八、基数排序 九、堆排序 十、希尔排序 十一、十大排序算法对比 十二、各算法详解与应用场景 1. 选择排序&#xff08;Selection Sort&#xff…...

解决神经网络输出尺寸过小的实战方案

训练CIFAR10分类模型时出现报错&#xff1a;RuntimeError: Given input size: (256x1x1). Calculated output size: (256x0x0). Output size is too small。该问题由网络结构设计缺陷导致图像尺寸过度缩小引发。 核心原因分析 网络结构缺陷 原始模型采用六层卷积层&#xff0c…...

Python备忘

1. 自定义多线程程序&#xff1a; import concurrent.futures import threadingclass CustomThreadPool:def __init__(self, max_workers):self.max_workers max_workersself.pool concurrent.futures.ThreadPoolExecutor(max_workers)self.running_num 0self.semaphore t…...

如何在 Windows 11 中永久更改默认浏览器:阻止 Edge 占据主导地位

在 Windows 11 中更改默认浏览器对于新手或技术不太熟练的用户来说可能会令人沮丧。 为什么要在 Windows 11 中更改默认浏览器? 这是一个重要的问题:你为什么要从 Microsoft Edge 切换过来? 生态系统集成:如果你已经在广泛使用 Google 服务,Chrome 可以提供无缝集成。同…...

量子比特实现方式

经典计算机是通过电子电路运转起来的。使用硅制半导体制成的名为晶体管的小元件发挥了开关的作用&#xff0c;将其与金属布线组合起来即可实现逻辑门&#xff0c;再将逻辑门集成起来就能制造出经典计算机。量子计算机的制造过程则要复杂许多&#xff0c;因为量子计算机既需要量…...

智慧水务发展迅猛:从物联网架构到AIoT系统的跨越式升级

AI大模型引领智慧水务迈入新纪元 2025年5月25日&#xff0c;水利部自主研发的“水利标准AI大模型”正式发布&#xff0c;它标志着水务行业智能化进程的重大突破。该模型集成1800余项水利标准、500余项法规及海量科研数据&#xff0c;支持立项、编制、审查等全流程智能管理&…...

1、cpp实现Python的print函数

实现一 #include <iostream> #include <list> #include <string>using namespace std;// 定义一个空的print函数&#xff0c;作为递归终止条件 void print(){// };// 可变参数模板函数&#xff0c;用于递归输出传入的参数 template <typename T, typenam…...

【Linux基础知识系列】第十四篇-系统监控与性能优化

一、简介 随着信息技术的飞速发展&#xff0c;Linux系统在服务器领域占据着重要地位。无论是web服务器、数据库服务器还是文件服务器&#xff0c;都需要高效的运行以满足业务需求。系统监控与性能优化是确保Linux系统稳定、高效运行的关键任务。通过实时监测系统资源的使用情况…...

云原生思维重塑数字化基座:从理念到实践的深度剖析

&#x1f4dd;个人主页&#x1f339;&#xff1a;慌ZHANG-CSDN博客 &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339; 一、引言&#xff1a;云原生为何成为数字化的“基础设施语言”&#xff1f; 随着5G、人工智能、物联网等技术逐步进入规模化落地阶段&am…...

Animate On Scroll 用于在用户滚动页面时实现元素的动画效果

AOS (Animate On Scroll) 详细介绍 什么是AOS&#xff1f; AOS&#xff08;Animate On Scroll&#xff09;是一个轻量级的JavaScript库&#xff0c;用于在用户滚动页面时实现元素的动画效果。它允许网页元素在进入或离开视口&#xff08;viewport&#xff09;时触发各种CSS动…...

Java高级 | 【实验五】Spring boot+mybatis操作数据库

隶书文章&#xff1a;Java高级 | &#xff08;二十二&#xff09;Java常用类库-CSDN博客 系列文章&#xff1a;Java高级 | 【实验一】Springboot安装及测试 |最新-CSDN博客 Java高级 | 【实验二】Springboot 控制器类相关注解知识-CSDN博客 Java高级 | 【实验三】Springboot 静…...

[蓝桥杯]搭积木

搭积木 题目描述 小明对搭积木非常感兴趣。他的积木都是同样大小的正立方体。 在搭积木时&#xff0c;小明选取 mm 块积木作为地基&#xff0c;将他们在桌子上一字排开&#xff0c;中间不留空隙&#xff0c;并称其为第 0 层。 随后&#xff0c;小明可以在上面摆放第 1 层&a…...

在MATLAB中使用自定义的ROS2消息

简明结论&#xff1a; 无论ROS2节点和MATLAB运行在哪&#xff0c;MATLAB本机都必须拥有自定义消息源码并本地用ros2genmsg生成&#xff0c;才能在Simulink里订阅这些消息。只要你想让MATLAB或Simulink能识别自定义消息&#xff0c;必须把消息包源码(.msg等)拷到本机指定目录&a…...

使用C/C++和OpenCV实现图像拼接

使用 C 和 OpenCV 实现图像拼接 本文将详细介绍如何利用 OpenCV 库&#xff0c;在 C 环境中实现图像拼接。图像拼接技术可以将多张具有重叠区域的图像合成为一张高分辨率的全景图。OpenCV 提供了一个功能强大的 Stitcher 类&#xff0c;它封装了从特征点检测、匹配到图像融合的…...

神经网络-Day46

目录 一、 什么是注意力二、 特征图的提取2.1 简单CNN的训练2.2 特征图可视化 三、通道注意力3.1 通道注意力的定义3.2 模型的重新定义&#xff08;通道注意力的插入&#xff09; 一、 什么是注意力 注意力机制&#xff0c;本质从onehot-elmo-selfattention-encoder-bert这就是…...

Ubuntu中常用的网络命令指南

Ubuntu中常用的网络命令指南 在Ubuntu系统中&#xff0c;网络管理是日常运维和故障排查的核心技能。 &#x1f6e0;️ 基础网络诊断 ping - 测试网络连通性 ping google.com # 持续测试 ping -c 4 google.com # 发送4个包后停止traceroute / tracepath - 追踪数据包路径 …...

JVM——如何打造一个类加载器?

引入 在Java应用程序的生命周期中&#xff0c;类加载器扮演着至关重要的角色。它是Java运行时环境的核心组件之一&#xff0c;负责在需要时动态加载类文件到JVM中。理解类加载器的工作原理以及如何自定义类加载器&#xff0c;不仅可以帮助我们更好地管理应用程序的类加载过程&…...

【MATLAB去噪算法】基于ICEEMDAN联合小波阈值去噪算法

ICEEMDAN联合小波阈值去噪算法相关文献 &#xff08;注&#xff1a;目前相关论文较少&#xff0c;应用该套代码可发直接一些水刊&#xff09; 一、CEEMDAN的局限性 模式残留噪声问题&#xff1a;原始CEEMDAN在计算每个IMF时直接对噪声扰动的信号进行模态分解并平均。 后果&a…...

c++ Base58编码解码

Base58 字符集 Base58 使用 58 个字符进行编码&#xff0c;字符集为&#xff1a;123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz。注意&#xff1a;0&#xff08;零&#xff09;、O&#xff08;大写字母O&#xff09;、I&#xff08;大写字母I&#xff09;和 l&a…...

证券交易柜台系统解析与LinkCounter解决方案开发实践

第一章 证券交易柜台系统基础解析 1.1 定义与行业定位 证券交易柜台系统&#xff08;Trading Counter System&#xff09;是券商经纪业务的核心支撑平台&#xff0c;承担投资者指令传输、风险控制、清算结算等职能。根据中国证监会《证券期货业网络信息安全管理办法》要求&am…...

XXTEA,XTEA与TEA

TEA、XTEA和XXTEA都是分组加密算法&#xff0c;它们在设计、安全性、性能等方面存在显著区别。以下是它们的主要区别&#xff1a; 密钥长度 TEA&#xff1a;使用128位密钥。 XTEA&#xff1a;通常使用128位或256位密钥。 XXTEA&#xff1a;密钥长度更灵活&#xff0c;可以使用任…...

机器人玩转之---嵌入式开发板基础知识到实战选型指南(包含ORIN、RDK X5、Raspberry pi、RK系列等)

1. 基础知识讲解 1.1 什么是嵌入式开发板&#xff1f; 嵌入式开发板是一种专门设计用于嵌入式系统开发的硬件平台&#xff0c;它集成了微处理器、内存、存储、输入输出接口等核心组件于单块印刷电路板上。与传统的PC不同&#xff0c;嵌入式开发板具有体积小、功耗低、成本适中…...

腾讯云国际版和国内版账户通用吗?一样吗?为什么?

在当今全球化的数字化时代&#xff0c;云计算服务成为众多企业和个人拓展业务、存储数据的重要选择。腾讯云作为国内领先的云服务提供商&#xff0c;其国际版和国内版备受关注。那么&#xff0c;腾讯云国际版和国内版账户是否通用&#xff1f;它们究竟一样吗&#xff1f;背后又…...

OrCAD X Capture CIS设计小诀窍系列第二季--03.如何在Capture中输出带有目录和元器件信息的PDF

背景介绍&#xff1a;我们在进行原理图设计时&#xff0c;经常需要输出PDF来查看或评审&#xff0c;但通过”Print”功能导出的PDF较为简单&#xff0c;只能查看设计视图&#xff1b;而通过使用Ghostscript软件可以输出带有目录和元器件信息的PDF&#xff0c;让设计师可以直接在…...

汽车的安全性能测试:试验台铁地板的重要性

汽车的安全性能测试是非常重要的&#xff0c;其中试验台铁地板的设计和材料选择起着至关重要的作用。试验台铁地板是指在进行汽车碰撞、侧翻等试验时&#xff0c;用于支撑汽车底部和提供稳定支撑的重要部件。 在进行汽车碰撞试验时&#xff0c;试验台铁地板的设计和材料需要具…...

Lua和JS的垃圾回收机制

Lua 和 JavaScript 都采用了 自动垃圾回收机制&#xff08;GC&#xff09; 来管理内存&#xff0c;开发者无需手动释放内存&#xff0c;但它们的 实现机制和行为策略不同。下面我们从原理、策略、优缺点等方面来详细对比&#xff1a; &#x1f536; 1. 基本原理对比 特性LuaJa…...

实践指南:从零开始搭建RAG驱动的智能问答系统

LLM 赋能的最强大的应用之一是复杂的问答 (Q&A) 聊天机器人。这些是可以回答关于特定来源信息问题的应用程序。这些应用程序使用一种称为检索增强生成的技术&#xff0c;或 RAG。本文将展示如何基于 LangChain 构建一个简单的基于非结构化数据文本数据源的问答应用程序。 温…...

边缘计算服务器

边缘计算服务器的核心要点解析&#xff0c;综合技术架构、应用场景与部署方案&#xff1a; 一、核心定义与技术特性‌ 本质定位‌ 部署在网络边缘侧的专用计算设备&#xff08;如工厂车间、智慧路灯等&#xff09;&#xff0c;直接处理终端设备&#xff08;传感器、摄像头等…...