学透Spring Boot — 010. 单元测试和Spring Test
系列文章目录
这是CSDN postnull 博客《学透Spring Boot》系列的一篇,更多文章请移步:Postnull - 学透Spring Boot系列文章
文章目录
- 系列文章目录
- 前言
- 1. 基本概念
- UT 单元测试
- TDD 测试驱动开发
- UT测试框架
- Mock框架
- 3. Spring Test
- 为什么要用Spring Test
- 引入Spring Test
- Spring Test最简单使用
前言
开发的过程中,写业务代码是工作的一部分,测试也是工作的一部分。尤其是作为开发人员,用单元测试来测试我们的代码,可以更早的发现bug。
1. 基本概念
UT 单元测试
单元测试 Unit Testing,通常是开发的一部分,也是开发过程中最小的测试单元。主要测试一个类或一个方法的逻辑。
因为只是保证我们自己写的代码的逻辑,所以是不涉及外部服务的(比如数据库和外部接口),外部服务我们通常使用mock来模拟它们的行为。
UT是代码片段的测试
外部集成测试才需要依赖真正的外部服务
TDD 测试驱动开发
近些年流行很多种 XDD,其中和测试相关的就是TDD,Test driven development,这是一种开发方法。
以前传统的开发模式,我们先一口气写完业务代码,然后再开始写单元测试。但是会遇到一些问题:
- 业务代码不方便测试
- 测试时才发现bug,导致业务代码要做很大的调整
所以我们可以换一种思路,先写测试用例,再写业务代码。
这也就是TDD的三个步骤,遵循 红-绿-重构(Red-Green-Refactor)
- 红:编写一个失败的测试。
- 绿:编写代码使测试通过。
- 重构:优化代码,确保测试仍然通过。
我们先快速试一下
先写个测试用例
public class CalculatorTest {@Testpublic void testAdd1() {Calculator calculator = new Calculator();assertEquals(3, calculator.add(1, 2));}@Testpublic void testAdd2() {Calculator calculator = new Calculator();assertEquals(0, calculator.add(1, -1));}
}
这个时候,测试用例是通不过的,因为我们的业务代码类都还没实现,编译错误。当然这样体验不太好,我们也可以先实现业务代码的骨架,只是空实现。
public class Calculator {public Integer add(int a, int b) {return null;}
}
我们运行一下测试用例,UT不通过,这也是预期的。

然后我们开始实现代码
public class Calculator {public Integer add(int a, int b) {return 0;}
}
这时候单元用例部分通过了

说明我们的代码有问题,继续调整
public class Calculator {public Integer add(int a, int b) {return a + b;}
}
这次我们的UT都过了,表示代码基本没问题了。(基本没问题不表示绝对没问题,因为可能测试覆盖率不够,有些边缘的case没有考虑到。)
下次,我们的业务代码被修改了,理论上出了bug,我们的测试用例是要失败的。
public class Calculator {public Integer add(int a, int b) {if(a < 0 || b < 0){return null;}return a + b;}
}

这时候,我们就需要注意了,是代码有问题,还是测试用例需要更新。
转换思路——测试先行
UT测试框架
Java最常用的 UT 框架有两个
- Junit
- TestNG
其中Junit比较轻量,满足大部分场景。TestNG功能更强大,比如支持并行测试(同时运行多个测试用例,Junit只能一个完了后再跑下一个)。具体对比:
- TestNG 的@DataProvider,注入测试数据更方便,Junit5后提供的@ParameteriedTest也差不多功能
- TestNG支持测试依赖,运行A用例前会自动先触发B用例
- TestNG支持测试分组,方便运行一组测试用例
- TestNG支持用例并行执行,对相对独立的case可以大大加快UT的时间
- ……
TestNG更强大,但有时简单就好
Mock框架
前面也说过,对于外部依赖,甚至是业务代码其它的类,我们都应该模拟,这样保证我们可以关注被测试的这个类和这个方法。
保证测试用例的能够独立、快速的被测试
有很多Mock框架
- Mockito:最常用
- PowerMock:兼容Mockito,功能更强大,比如测试静态方法和私有方法(反思:private方法真的应该被测试吗)
比如使用Mockito,步骤基本都是差不多的,先创建mock对象和行为,然后调用方法,最后验证结果
public class UserServiceTest {@Testpublic void testGetUser() {// 1. 创建 Mock 对象UserRepository mockRepo = mock(UserRepository.class);// 2. 设置 Mock 行为when(mockRepo.findById(1)).thenReturn(new User(1, "John"));// 3. 调用测试方法UserService userService = new UserService(mockRepo);User user = userService.getUser(1);// 4. 验证结果assertEquals("John", user.getName());}
}
3. Spring Test
为什么要用Spring Test
对于Java项目,直接使用TestNG/Junit + Mockito 不就可以了吗?为什么还要用 Spring Test?
以前也有这个疑问,但是如果我们测试Spring 项目时,Junit + Mockito 就有点力不从心了。比如:
- 注入Spring的配置,比如application-test.xml中配置,注入到Spring容器中去
- 自动注入Bean,这个做不到,得手动new对象
- 模拟HTTP请求,这个也做不到,所以Controller测试不了
- 测试Spring整个应用,也做不到,只能测试单个类
Spring Test就是为了更方便的测试Spring 应用
当然,Spring Test不是要取代 TestNG/Junit + Mockito, 想法,它底层用的还是这些技术。
它只是提供了一堆工具和注解,帮助我们更方便测试Spring应用。
引入Spring Test
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope>
</dependency>
我们在关联依赖中也可以看到,它自动引入了Junit和Mockito

这框架本身包含了两个模块
- Spring Test 核心模块
spring-boot-test - 自动配置模块
spring-boot-test-autoconfigure: 我们很多自动配置,比如注入

比如在自动配置的模块中,我们可以看到MockMvc的自动配置。这个类我们以后测试会经常遇到。
Spring Test最简单使用
本文我们先来个最简单的例子,测试我们的Controller。
@RestController
@RequestMapping("/tn-users")
public class TnUserController {private TnUserService tnUserService;public TnUserController(TnUserService tnUserService) {this.tnUserService = tnUserService;}@GetMapping("/{id}")public ResponseEntity<TypiUser> getUser(@PathVariable int id) {TypiUser user = tnUserService.getUserById(id);return user != null ? ResponseEntity.ok(user) : ResponseEntity.notFound().build();}
}
然后我们编写测试用例
@WebMvcTest(TnUserController.class)
public class TnUserControllerTest {@Autowiredprivate MockMvc mockMvc;@MockitoBeanprivate TnUserService tnUserService;@Test@DisplayName("测试成功查询用户的情况")public void testGetUser() throws Exception {//givenTypiUser mockUser = TypiUser.builder().id(1234).name("Joe").build();//whenwhen(tnUserService.getUserById(eq(1234))).thenReturn(mockUser);//thenmockMvc.perform(get("/tn-users/{id}", 1234)).andExpect(status().isOk()).andExpect(jsonPath("$.id").value(1234)).andExpect(jsonPath("$.name").value("Joe"));}
}
测试通过

稍微改一下代码,再次运行,会发现报错。
mockMvc.perform(get("/tn-users/{id}", 1234)).andExpect(status().isBadRequest());

可以看到,我们现在具备测试Controller层的能力了。如果没有Spring Test,只是靠Mockito基本做不到接口层的测试。
我们先不用关注实现的细节。下一篇文章我们会全面介绍Spring Test的使用。
相关文章:
学透Spring Boot — 010. 单元测试和Spring Test
系列文章目录 这是CSDN postnull 博客《学透Spring Boot》系列的一篇,更多文章请移步:Postnull - 学透Spring Boot系列文章 文章目录 系列文章目录前言1. 基本概念UT 单元测试TDD 测试驱动开发UT测试框架Mock框架 3. Spring Test为什么要用Spring Test引…...
TortoiseGit多账号切换配置
前言 之前配置好的都是,TortoiseGit与Gitee之间的提交,突然有需求要在GitHub上提交,于是在参考网上方案和TortoiseGit的帮助手册后,便有了此文。由于GitHub已经配置完成,所以下述以配置Gitee为例。因为之前是单账号使用…...
3D 地图渲染-区域纹理图添加
引入-初始化地图(关键代码) // 初始化页面引入高德 webapi -- index.html 文件 <script src https://webapi.amap.com/maps?v2.0&key您申请的key值></script>// 添加地图容器 <div idcontainer ></div>// 地图初始化应该…...
【Linux】条件变量封装类及环形队列的实现
📢博客主页:https://blog.csdn.net/2301_779549673 📢博客仓库:https://gitee.com/JohnKingW/linux_test/tree/master/lesson 📢欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正! &…...
离线部署kubesphere(已有k8s和私有harbor的基础上)
前言说明:本文是在已有k8s集群和私有仓库harbor上进行离线安装kubesphere;官网的离线教程写都很详细,但是在部署部份把搭建集群和搭建仓库也写一起了,跟着做踩了点坑,这里就记录下来希望可以帮助到需要的xdm。 1.根据官…...
非阻塞IO,fcntl,多路转接,select,poll,epoll,reactor
IO次数会影响程序的效率,在编程中往往会尽量减少IO次数,用以提高程序的效率,例如缓冲区,就是减少IO次数提高效率的一种方式;而IO影响效率的最大原因其实是因为IO等拷贝,在进行IO时往往需要拷贝的数据就绪,或…...
Redis常用的数据结构及其使用场景
字符串(String) string 是 redis 最基本的类型,你可以理解成与 Memcached 一模一样的类型,一个 key 对应一个 value。 string 类型是二进制安全的。意思是 redis 的 string 可以包含任何数据,比如jpg图片或者序列化的对象。 string 类型是 R…...
PhotoShop学习04
1.背景图层 最下面的被锁锁住的图层为背景图层,背景图层充当整个图层的背景,名字标注为背景,无法修改背景图层的排序始终位于图层最底部。 当我想把上方的图层移动到背景图层之后,发现无法移动图层无法移动,把背景图层…...
服务器有2张显卡,在别的虚拟环境部署运行了Xinference,然后又建个虚拟环境再部署一个可以吗?
环境: 云服务器Ubuntu系统 2张 NVIDIA H20 96GB Qwen2.5-VL-72B-Instruct-AWQ Qint4量化 AWQ 是 “Activation - Aware Weight Quantization” 的缩写,即激活感知权重量化。它是一种针对大型模型的先进量化算法,通过在权重量化过程中引入对激活值的感知,最小化量化误差…...
K8s中CPU和Memory的资源管理
资源类型 在 Kubernetes 中,Pod 作为最小的原子调度单位,所有跟调度和资源管理相关的属性都属于 Pod。其中最常用的资源就是 CPU 和 Memory。 CPU 资源 在 Kubernetes 中,一个 CPU 等于 1 个物理 CPU 核或者一个虚拟核,取决于节…...
任务挂起和恢复
任务挂起和恢复API函数 下面用按键和震动传感器验证任务挂起和恢复API函数: PA7接震动传感器,按键引脚为PA0,提前初始化好GPIO引脚 key.c #include "key.h" #include "stm32f10x.h"void KeyInit() {GPIO_InitTypeDef …...
【NLP 55、投机采样加速推理】
目录 一、投机采样 二、投机采样改进:美杜莎模型 流程 改进 三、Deepseek的投机采样 流程 Ⅰ、输入文本预处理 Ⅱ、引导模型预测 Ⅲ、候选集筛选(可选) Ⅳ、主模型验证 Ⅴ、生成输出与循环 骗你的,其实我在意透了 —— 25.4.4 一、…...
如何在 Windows 上安装 Python
Python是一种高级编程语言,由于其简单性、多功能性和广泛的应用范围而变得越来越流行。如何在 Windows 操作系统中安装 Python 的过程相对简单,只需几个简单的步骤。 本文旨在指导您完成在 Windows 计算机上下载和安装 Python 的过程。 如何在 Windows…...
【Groovy快速上手 ONLY ONE】Groovy与Java的核心差异
最近在使用的平台上写脚本的语言是Groovy,所以也学习一下,作为 Java 开发者,Groovy 对我们来说会非常友好,而且它的语法更简洁且支持动态类型,所以其实了解下Java和Groovy的差异点就可以快速上手了,以下是 …...
计算机系统---CPU
定义与功能 中央处理器(Central Processing Unit,CPU),是电子计算机的主要设备之一,是计算机的核心部件。CPU是计算机的运算核心和控制核心,负责执行计算机程序中的指令,进行算术运算、逻辑运算…...
WEB安全--提权思路
一、情形 在我们成功上传webshell到服务器中并拿到权限时,发现我们的权限很低无法执行特定的命令,这时为了能做更多的操作,我们就需要提升权限。 二、方式 2.1、Windows提权 1、普通用户执行systeminfo命令获取服务器的基本信息࿰…...
多layout 布局适配
安卓多布局文件适配方案操作流程 以下为通过多套布局文件适配不同屏幕尺寸/密度的详细步骤,结合主流适配策略及最佳实践总结: 一、创建多套布局资源目录 按屏幕尺寸划分 在 res 目录下创建以下文件夹(根据设备特性自动匹配ÿ…...
selectdb修改表副本
如果想修改doris(也就是selectdb数据库)表的副本数需要首先确定是否分区表,当前没有数据字典得知哪个表是分区的,只能先show partitions看结果 首先,副本数不应该大于be节点数 其次,修改期间最好不要跑业务…...
Metabase:一个免费开源的BI平台
今天给大家介绍一个开源数据可视化分析工具:Metabase。它可以帮助用户快速连接数据库、执行查询并创建交互式仪表盘,即使非技术人员也能快速上手。 Metabase 支持多种数据源,包括 MySQL、PostgreSQL、Oracle、SQL Server、SQLite、MongoDB、P…...
第15届蓝桥杯省赛python组A,B,C集合
过几天就省赛了,一直以来用的是C,Python蓝桥杯也是刚刚开始准备(虽然深度学习用的都是python,但是两者基本没有任何关系),这两天在做去年题时犯了很多低级错误,因此记录一下以便自己复查 PS&am…...
AWS 云运维管理指南
一、总体目标 高可用性:通过跨可用区 (AZ) 和跨区域 (Region) 的架构设计,确保系统运行可靠。性能优化:优化AWS资源使用,提升应用性能。安全合规:利用AWS内置安全服务,满足行业合规要求(如GDPR、ISO 27001、等保2.0)。成本管控:通过成本优化工具,减少浪费,实现FinOp…...
为什么有的深度学习训练,有训练集、验证集、测试集3个划分,有的只是划分训练集和测试集?
在机器学习和深度学习中,数据集的划分方式取决于任务需求、数据量以及模型开发流程的严谨性。 1. 三者划分:训练集、验证集、测试集 目的 训练集(Training Set):用于模型参数的直接训练。验证集(Validati…...
虚拟现实 UI 设计:打造沉浸式用户体验
VR UI 设计基础与特点 虚拟现实技术近年来发展迅猛,其独特的沉浸式体验吸引了众多领域的关注与应用。在 VR 环境中,UI 设计扮演着至关重要的角色,它是用户与虚拟世界交互的桥梁。与传统 UI 设计相比,VR UI 设计具有显著的特点。传…...
前端Uniapp接入UviewPlus详细教程!!!
相信大家在引入UviewPlusUI时遇到很头疼的问题,那就是明明自己是按照官网教程一步一步的走,为什么到处都是bug呢?今天我一定要把这个让人头疼的问题解决了! 1.查看插件市场 重点: 我们打开Dcloud插件市场搜素uviewPl…...
【性能优化点滴】odygrd/quill在编译期做了哪些优化
Quill 是一个高性能的 C 日志库,它在编译器层面进行了大量优化以确保极低的运行时开销。以下是 Quill 在编译器优化方面的关键技术和实现细节: 1. 编译时字符串解析与格式校验 Quill 在编译时完成格式字符串的解析和校验,避免运行时开销&…...
02 反射 泛型(II)
目录 一、反射 1. 反射引入 2. 创建对象 3. 反射核心用法 二、泛型 1. 泛型的重要性 (1)解决类型安全问题 (2)避免重复代码 (3)提高可读性和维护性 2. 泛型用法 (1)泛型类 …...
Spring Boot 七种事务传播行为只有 REQUIRES_NEW 和 NESTED 支持部分回滚的分析
Spring Boot 七种事务传播行为支持部分回滚的分析 支持部分回滚的传播行为 REQUIRES_NEW:始终开启新事务,独立于外部事务,失败时仅自身回滚。NESTED:在当前事务中创建保存点(Savepoint),可局部…...
ZLMediaKit 源码分析——[5] ZLToolKit 中EventPoller之延时任务处理
系列文章目录 第一篇 基于SRS 的 WebRTC 环境搭建 第二篇 基于SRS 实现RTSP接入与WebRTC播放 第三篇 centos下基于ZLMediaKit 的WebRTC 环境搭建 第四篇 WebRTC学习一:获取音频和视频设备 第五篇 WebRTC学习二:WebRTC音视频数据采集 第六篇 WebRTC学习三…...
元宇宙浪潮下,前端开发如何“乘风破浪”?
一、元宇宙对前端开发的新要求 元宇宙的兴起,为前端开发领域带来了全新的挑战与机遇。元宇宙作为一个高度集成、多维互动的虚拟世界,要求前端开发不仅具备传统网页开发的能力,还需要掌握虚拟现实(VR)、增强现实&#…...
2025年3月 Scratch 图形化(二级)真题解析 中国电子学会全国青少年软件编程等级考试
2025.03Scratch图形化编程等级考试二级真题试卷 一、选择题 第 1 题 甲、乙、丙、丁、戊五人参加100米跑比赛,甲说:“我的前面至少有两人,但我比丁快。”乙说:“我的前面是戊。”丙说:“我的后面还有两个人。”请从前往后(按照速度快慢&a…...
