Spring Boot单元测试
什么是单元测试?
单元测试(unit testing),是指对软件中的最小可测试单元进行检查和验证的过程就叫单元测试。
单元测试是开发人员编写的一小段代码,用于检验被测代码的一个很小的、很明确的(代码) 功能是否正确。执行单元测试就是为了证明某段代码的执行结果是否符合我们的预期。如果测试结果符合我们的预期,称之为测试通过,否则就是测试未通过(或者叫测试失败)
Java 中的最小测试单元就到方法了,也就说对方法的测试就是单元测试
单元测试的作用
在没有接触单元测试之前我们是怎么做测试的?一般有三个方法:
| 方式 | 弊端 |
|---|---|
| 启动整个应用像用户正常操作一样,操作界面调用接口 | 每次测试都需要启动整个项目 |
| 在代码某个地方写一个临时入口,例如main方法测试 | 用完就删除不然影响项目运行速度或效率 |
| 利用postman工具调用接口 | 每次测试启动服务 |
在时间允许的情况下,编写单元测试是程序员对代码的自测,这是对自己代码的负责。
写单元测试的两个动机:
- 保证或验证实现功能。
- 保护已经实现的功能不被破坏。
Spring Boot引入单元测试
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope>
</dependency>
注解的使用
| 注解 | 作用 |
|---|---|
| @SpringBootTest | 获取启动类,加载配置,寻找主配置启动类 |
| @RunWith(SpringRunner.class) | 让JUnit运行Spring的测试环境,获得Spring环境的上下文的支持 |
@RunWith(SpringRunner.class)
@SpringBootTest
public class ApplicationTest {
}
@SpringBootTest 重要参数
- args
应用程序参数,如:args = “–app.test=one” - classes
Spring Boot应用启动入口类名,该参数不指定时由Spring Boot默认查找。 - webEnvironment
默认情况下@SpringBootTest不会启动服务器。当测试Web应用时,需指定该参数以便加载上下文环境。
WebEnvironment枚举值说明:
- MOCK
默认值,加载WebApplicationContext并提供模拟Web环境。使用此注释时,不会启动嵌入式服务器。 - RANDOM_PORT
启动应用并随机监听一个端口。 - DEFINED_PORT
启动应用并监听自定义的端口(来自application.properties)或使用默认端口8080。 - NONE
ApplicationContext通过使用加载,SpringApplication但不提供任何网络环境(模拟或其他方式)。
工具Junit4
注解的使用
| 注解 | 作用 |
|---|---|
| @Test | 编写一般测试用例用 |
| @Test(timeout = 1000) | 测试方法执行超过1000毫秒后算超时,测试将失败 |
| @Test(expected = Exception.class) | 测试方法期望得到的异常类,如果方法执行没有抛出指定的异常,则测试失败。 |
| @Before | 在每个方法测试前执行,一般用来初始化方法(比如我们在测试别的方法时,类中与其他测试方法共享的值已经被改变,为了保证测试结果的有效性,我们会在@Before注解的方法中重置数据) |
| @After | 在每个测试方法执行后,在方法执行完成后要做的事情 |
| @BeforeClass | 在所有测试方法执行前执行 |
| @AfterClass | 在所有测试方法执行后执行 |
| @Ignore | 修饰的类或方法会被测试运行器忽略 |
| @RunWith | 在 Junit 中有很多个 Runner,他们负责调用你的测试代码,每一个 Runner 都有各自的特殊功能,你根据需要选择不同的 Runner 来运行你的测试代码 |
什么是Mock
在面向对象的程序设计中,模拟对象(英语:mock object)是以可控的方式模拟真实对象行为的假对象。在编程过程中,通常通过模拟一些输入数据,来验证程序是否达到预期结果。
为什么使用Mock对象
使用模拟对象,可以模拟复杂的、真实的对象行为。如果在单元测试中无法使用真实对象,可采用模拟对象进行替代。
spring测试框架提供了两种方式,独立安装和集成Web环境测试(此种方式并不会集成真正的web环境,而是通过相应的Mock API进行模拟测试,无须启动服务器)
Java的Mockito框架
Mockito是一款用于java开发的mock测试框架,用于快速创建和配置mock对象。通过创建外部依赖的 Mock 对象, 然后将此 Mock 对象注入到测试类中,简化有外部依赖的类的测试。
MockMvc的概念
MockMvc是由spring-test包提供,实现了对Http请求的模拟,能够直接使用网络的形式,转换到Controller的调用,使得测试速度快、不依赖网络环境。同时提供了一套验证的工具,结果的验证十分方便。
接口MockMvcBuilder,提供一个唯一的build方法,用来构造MockMvc。主要有两个实现:StandaloneMockMvcBuilder和DefaultMockMvcBuilder。
StandaloneMockMvcBuilder:指定 WebApplicationContext,它将会从该上下文获取相应的控制器并得到相应的 MockMvc
@RunWith(SpringRunner.class)
@SpringBootTest
public class UserControllerTest {@Autowiredprivate WebApplicationContext webApplicationContext;private MockMvc mockMvc;@Beforepublic void setUp() throws Exception {mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
}
DefaultMockMvcBuilder:通过参数指定一组控制器,这样就不需要从上下文获取了
@RunWith(SpringRunner.class)
@SpringBootTest
public class UserControllerTest {private MockMvc mockMvc;@Beforepublic void setUp() throws Exception {mockMvc = MockMvcBuilders.standaloneSetup(new UserController()).build();}
}
// ...
import static org.hamcrest.Matchers.containsString;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;@RunWith(SpringRunner.class)
@SpringBootTest
public class UserControllerTest {@Autowiredprivate WebApplicationContext webApplicationContext;private MockMvc mockMvc;@Beforepublic void setUp() {mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();}@Testpublic void getUser() {mockMvc.perform(get("/v1/users/1").accept(MediaType.APPLICATION_JSON_UTF8)).andExpect(status().isOk()).andExpect(content().string(containsString("\"name\":\"lyTongXue\"")));}}
MockMVC的基本步骤
(1) mockMvc.perform执行一个请求。
(2) MockMvcRequestBuilders.get(“XXX”)构造一个请求。
(3) ResultActions.param添加请求传值
(4) ResultActions.accept设置返回类型
(5) ResultActions.andExpect添加执行完成后的断言。
(6) ResultActions.andDo添加一个结果处理器,表示要对结果做点什么事情,比如处使用print输出整个响应结果信息。
(7) ResultActions.andReturn表示执行完成后返回相应的结果。
| 方法名 | 描述 |
|---|---|
| Mockito.mock(classToMock) | 模拟对象 |
| Mockito.verify(mock) | 验证行为是否发生 |
| Mockito.when(methodCall).thenReturn(value1).thenReturn(value2) | 触发时第一次返回value1,第n次都返回value2 |
| Mockito.doThrow(toBeThrown).when(mock).[method] | 模拟抛出异常。 |
| Mockito.mock(classToMock,defaultAnswer) | 使用默认Answer模拟对象 |
| Mockito.when(methodCall).thenReturn(value) | 参数匹配 |
| Mockito.doReturn(toBeReturned).when(mock).[method] | 参数匹配(直接执行不判断) |
| Mockito.when(methodCall).thenAnswer(answer)) | 预期回调接口生成期望值 |
| Mockito.doAnswer(answer).when(methodCall).[method] | 预期回调接口生成期望值(直接执行不判断) |
| Mockito.spy(Object) | 用spy监控真实对象,设置真实对象行为 |
| Mockito.doNothing().when(mock).[method] | 不做任何返回 |
| Mockito.doCallRealMethod().when(mock).[method] //等价于Mockito.when(mock.[method]).thenCallRealMethod(); | 调用真实的方法 |
| reset(mock) | 重置mock |
使用断言
简单的断言说明
| 方法名 | 描述 |
|---|---|
| assertEquals | 判断两个对象或两个原始类型是否相等 |
| assertNotEquals | 判断两个对象或两个原始类型是否不相等 |
| assertSame | 判断两个对象引用是否指向同一个对象 |
| assertNotSame | 判断两个相关对象是否不指向同一个对象 |
| assertTrue | 判断给定的布尔值是否为true |
| assertFalse | 判断给定的布尔值是否为false |
| assertNull | 判断给定的对象引用是否为null |
| assertNotNull | 判断给定的对象引用是否不为null |
单元测试生成插件
TestMe插件可以智能分析被测试类的依赖类,结合Mockito+Junit等单元测试框架,生成Mock/InjectMocks依赖关系,自动生成单元测试类。
下载插件
File——>Settings——>Plugins,搜索TestMe,然后install就好了,插件安装完成后需要重启一下。
我们打开一个类,这个类就是我们即将要作为实验的类。光标定位到代码里,右击鼠标选择Generate…选择TestMe…后弹出Test Class,选择的是Junit4。

单元测试规范
1、单元测试代码必须写在如下工程目录 src/test/java,不允许写在业务代码目录下。
2、单元测试的基本目标:语句覆盖率达到 70%;核心模块的语句覆盖率和分支覆盖率都要达到 100%。
3、在工程规约的应用分层中提到的 DAO 层,Manager 层,可重用度高的 Service,都应该进行单元测试。
4、编写单元测试代码遵守 BCDE 原则,以保证被测试模块的交付质量。
阿里巴巴 Java 开发手册 \9. 【推荐】编写单元测试代码遵守 BCDE 原则,以保证被测试模块的交付质量。
Border:边界值测试,包括循环边界、特殊取值、特殊时间点、数据顺序等;
Correct:正确的输入,并得到预期的结果;
Design:与设计文档相结合,来编写单元测试;
Error:强制错误信息输入(如:非法数据、异常流程、非业务允许输入等),并得到预期的结果;
5、对于数据库相关的查询,更新,删除等操作,不能假设数据库里的数据是存在的, 或者直接操作数据库把数据插入进去,请使用程序插入或者导入数据的方式来准备数据。
6、和数据库相关的单元测试,可以设定自动回滚机制,不给数据库造成脏数据。或者 对单元测试产生的数据有明确的前后缀标识。
7、对于不可测的代码建议做必要的重构,使代码变得可测,避免为了达到测试要求而书写不规范测试代码。
8、在设计评审阶段,开发人员需要和测试人员一起确定单元测试范围,单元测试最好覆盖所有测试用例。
9、单元测试作为一种质量保障手段,不建议项目发布后补充单元测试用例,建议在项目提测前完成单元测试。
10、为了更方便地进行单元测试,业务代码应避免以下情况:
构造方法中做的事情过多
存在过多的全局变量和静态方法
存在过多的外部依赖
存在过多的条件语句。说明:多层条件语句建议使用卫语句、策略模式、状态模式等方式重构
11、不要对单元测试存在如下误解:
那是测试同学干的事情
单元测试代码是多余的。系统的整体功能与各单元部件的测试正常与否是强相关的
单元测试代码不需要维护,一年半载后,那么单元测试几乎处于废弃状态
单元测试与线上故障没有辩证关系,好的单元测试能够最大限度地规避线上故障
相关文章:
Spring Boot单元测试
什么是单元测试? 单元测试(unit testing),是指对软件中的最小可测试单元进行检查和验证的过程就叫单元测试。 单元测试是开发人员编写的一小段代码,用于检验被测代码的一个很小的、很明确的(代码) 功能是否正确。执行单元测试就是为了证明某…...
实景三维浪潮翻涌,新技术“席卷”石家庄!
5月11日,“全自主、全流程、全覆盖”2023实景三维新技术研讨会石家庄站暨航测与遥感学术交流会在石家庄凯旋金悦大酒店圆满举行。 本次会议由中国测绘学会、中国地理信息产业协会指导,河北省测绘学会、河北省地理信息产业协会主办,武汉大势智…...
【Python】使用小脚本
本文整理了我在学习和工作中用到的实用python脚本,希望也能帮助到需要的小伙伴~ 文章目录 视频格式转换顺序遍历文件夹中的文件 视频格式转换 安装视频处理库moviepy pip install moviepy安装FFmpeg(FFmpeg是一个开源的多媒体框架,moviepy…...
技术日志2023-5-18
1、Java远程调试 可参考:https://kefeng.wang/2018/03/06/idea-remote-debug/ 2、用户中心这样的基础项目有什么用,感觉非常鸡肋。 今天开发讨论中涉及到了用户中心,感觉在项目中使用用户中心只是给业务系统发一个token,业务系…...
JUC之锁
公平锁、非公平锁 公平锁指的是多线程按照申请锁的顺序来获取锁; 非公平锁指的是多线程不按照申请锁的顺序来获取锁。可能会出现优先级反转(后者居上) 公平锁为了保证线程申请顺序,势必要付出一定的性能代价,因此其吞…...
C++中的 cout 和 printf 用法
文章目录 前言cout & printfexampleprintf输出string字符串总结 前言 C是一种面向对象的编程语言,它继承了C语言的特点,同时也增加了许多新的特性。在C中的cout 和 printf是两种常用的输出函数,它们都可以将数据显示在屏幕上,…...
Maven基础使用
Maven 学习目标 理解Maven的用途掌握Maven的基本操作掌握Maven如何创建Web项目 Maven是什么 面临问题 在学习Maven之前,我们先来看一下我们现在做的项目都有哪些问题。假设你现在做了一个crm的系统,项目中肯定要用到一些jar包,比如说myb…...
【C++ 入坑指南】(06)运算符
文章目录 一、算术运算符二、赋值运算符三、比较运算符四、逻辑运算符五、算法题5.1、拆分位数 运算符是一种告诉编译器执行特定的数学或逻辑操作的符号。C 内置了丰富的运算符,并提供了以下类型的运算符: 运算符类型作用算术运算符用于处理四则运算赋值…...
了解一下js中的函数式编程
js中的函数式编程是一种编程范式,它将函数作为一等公民来使用。 在函数式编程中,函数是一种特殊的对象,可以赋值给变量、作为参数传递给其他函数、或作为其他函数的返回值。 函数式编程强调了函数的纯函数性,即函数输入相同时&a…...
动态HTTP代理在linux里的使用
动态HTTP代理是一种可以自动切换代理IP地址的代理方式,可以有效地绕过一些限制访问的网站。在Linux系统中,可以使用Privoxy和Proxychains来实现动态HTTP代理。 以下是在Linux中使用动态HTTP代理的步骤: 1. 安装Privoxy和Proxychains 在终端中…...
软考证书值得考吗?怎么考?
软考证书是什么?有什么用处?必须先明确这两个问题,才能有复习和考取的动力。怎么考过?这是第二步要着重解决的问题。今天详细帮助大家分析一下。 软考是国家级考试,具有强大的权威性与公信力。 软考全称为计算机技术…...
超级秘密文件夹忘记密码的解决办法
超级秘密文件夹是一款非常特殊的文件夹加密软件,它来无影去无踪,在安装后不会留下任何痕迹,只能通过软件热键才能打开。那么如果在使用过程中忘记了密码,这时我们该怎么办呢?下面我们就来了解一下。 首先,我…...
脑的物理系统
⼤脑模块化 人脑是一个复杂的网络,一般将大脑划分为不同的区域(即节点),并使用某种方法表征大脑区域之间的关系(即连接的边)来构建人脑网络。在功能磁共振成像(fMRI)数据的网络模型…...
1054. 距离相等的条形码(leetcode,堆问题,priority_queue)-------------------c++实现
1054. 距离相等的条形码(leetcode,堆问题,priority_queue)-------------------c实现 题目表述 在一个仓库里,有一排条形码,其中第 i 个条形码为 barcodes[i]。 请你重新排列这些条形码,使其中任意两个相…...
QT开发实战-动态壁纸软件
动态壁纸软件开发 项目源代码在下面链接获取: ----------------------------- 开发者:CodeSharkSJ 希望此项目能加强你对Qt的应用 文章目录 项目图与开发环境核心技术原理自定义窗口程序UI布局背景绘制样式表基本实现QWebEngineQMedia使用系统托盘隐藏记忆功能应用程序打包 …...
Netty核心组件模块(一)
1.Bootstrap和ServerBootstrap 1>.Bootstrap意思是引导,一个Netty应用通常由一个Bootstrap开始,主要作用是配置整个Netty程序,串联各个组件,Netty中Bootstrap类是客户端程序的启动引导类,ServerBootstrap是服务端启动引导类; 2>.常见的方法有: ①.public ServerBootstr…...
Robot Framework+Jenkins持续集成UI自动化项目
使用Robot Framework框架可进行Web端和APP端的UI自动化测试,为方便定时执行,可将Robot Framework的自动化项目持续集成至Jenkins平台,具体的操作步骤如下: 安装Jenkins的步骤如下: 手把手教小白安装Jenkins_程序员馨馨…...
【ROS】ROS1编程速览
1、简述 很多项目已经转向ROS2,本人作为ROS小白从ROS1开始学起,但是不会深入学习ROS1,只一带而过。 下面只了解一些ROS1中的概念和基本编程接口。 ROS1中有两种通信模式:话题模式和服务模式,区别如下 2、话题模式 …...
探索智能化:TOOM解析未来稿件校验系统的技术进展与应用展望
在信息时代,随着大数据、人工智能和自然语言处理等技术的快速发展,稿件校验系统正朝着智能化的方向迈进。智能化的稿件校验系统能够更准确、高效地检测虚假信息、抄袭行为以及提升文章质量。本文将探讨智能化稿件校验系统的技术进展与应用展望࿰…...
Java程序员从青铜到王者,不同段位的薪资和技能变化
想要薪资高,段位就得跟上,对于Java程序员来说,从青铜到王者,需要经历多个阶段,每个阶段需要掌握的技能都不一样。 今天,我们一起来看看每个段位都有什么特点、需要具备哪些“大杀”技能,也看看…...
挑战杯推荐项目
“人工智能”创意赛 - 智能艺术创作助手:借助大模型技术,开发能根据用户输入的主题、风格等要求,生成绘画、音乐、文学作品等多种形式艺术创作灵感或初稿的应用,帮助艺术家和创意爱好者激发创意、提高创作效率。 - 个性化梦境…...
vscode里如何用git
打开vs终端执行如下: 1 初始化 Git 仓库(如果尚未初始化) git init 2 添加文件到 Git 仓库 git add . 3 使用 git commit 命令来提交你的更改。确保在提交时加上一个有用的消息。 git commit -m "备注信息" 4 …...
微信小程序云开发平台MySQL的连接方式
注:微信小程序云开发平台指的是腾讯云开发 先给结论:微信小程序云开发平台的MySQL,无法通过获取数据库连接信息的方式进行连接,连接只能通过云开发的SDK连接,具体要参考官方文档: 为什么? 因为…...
成都鼎讯硬核科技!雷达目标与干扰模拟器,以卓越性能制胜电磁频谱战
在现代战争中,电磁频谱已成为继陆、海、空、天之后的 “第五维战场”,雷达作为电磁频谱领域的关键装备,其干扰与抗干扰能力的较量,直接影响着战争的胜负走向。由成都鼎讯科技匠心打造的雷达目标与干扰模拟器,凭借数字射…...
Element Plus 表单(el-form)中关于正整数输入的校验规则
目录 1 单个正整数输入1.1 模板1.2 校验规则 2 两个正整数输入(联动)2.1 模板2.2 校验规则2.3 CSS 1 单个正整数输入 1.1 模板 <el-formref"formRef":model"formData":rules"formRules"label-width"150px"…...
算法:模拟
1.替换所有的问号 1576. 替换所有的问号 - 力扣(LeetCode) 遍历字符串:通过外层循环逐一检查每个字符。遇到 ? 时处理: 内层循环遍历小写字母(a 到 z)。对每个字母检查是否满足: 与…...
LLMs 系列实操科普(1)
写在前面: 本期内容我们继续 Andrej Karpathy 的《How I use LLMs》讲座内容,原视频时长 ~130 分钟,以实操演示主流的一些 LLMs 的使用,由于涉及到实操,实际上并不适合以文字整理,但还是决定尽量整理一份笔…...
【 java 虚拟机知识 第一篇 】
目录 1.内存模型 1.1.JVM内存模型的介绍 1.2.堆和栈的区别 1.3.栈的存储细节 1.4.堆的部分 1.5.程序计数器的作用 1.6.方法区的内容 1.7.字符串池 1.8.引用类型 1.9.内存泄漏与内存溢出 1.10.会出现内存溢出的结构 1.内存模型 1.1.JVM内存模型的介绍 内存模型主要分…...
【LeetCode】3309. 连接二进制表示可形成的最大数值(递归|回溯|位运算)
LeetCode 3309. 连接二进制表示可形成的最大数值(中等) 题目描述解题思路Java代码 题目描述 题目链接:LeetCode 3309. 连接二进制表示可形成的最大数值(中等) 给你一个长度为 3 的整数数组 nums。 现以某种顺序 连接…...
MySQL:分区的基本使用
目录 一、什么是分区二、有什么作用三、分类四、创建分区五、删除分区 一、什么是分区 MySQL 分区(Partitioning)是一种将单张表的数据逻辑上拆分成多个物理部分的技术。这些物理部分(分区)可以独立存储、管理和优化,…...
