我想我大抵是疯了,我喜欢上了写单元测试
前言
大家好我是聪。相信有不少的小伙伴喜欢写代码,但是对于单元测试这些反而觉得多此一举,想着我都在接口文档测过了!还要写什么单元测试!写不了一点!!
由于本人也是一个小小程序猿🙉,我以前也不喜欢写,最近给扔到了另一个 leader 的项目组里面,刚进去他给我下达的命令就是,你写的代码逻辑都要给我写上单元测试,而且要生成覆盖率报告给我!哇!我顿时就难受了,我之前都没有这么严格的,但是呢最近在我疯狂的写单元测试下,我发现我爱上了写单元测试。
单元测试的成长历程
第一次接触单元测试,还是在大学的测试课程里面。老师巴拉巴拉的讲,我虽然能听懂,但是不知道有啥用,课程作业反正做起来也没啥难度,反正能输出完事。
还有些接触单元测试就是平时学习视频的时候,跟着博主教的敲,这种简单的比如测试一个Mybatis 查询功能的单元测试,在我之前看来,soso 我直接用 swagger 文档请求岂不是更方便,代码都不用写咯。
直到我接触到了公司项目的单元测试,刚来公司看见之前的老项目单元测试都是成堆成堆的写,我也不是很理解,由于老项目的负责员工不知道换了多少代,新负责的都没调试过单元测试,直接代码改动,导致项目现在的单元测试很多环境配置都没及时更新,无法正常启动。当然也没人理会💥。
最近接触单元测试就是来到了新项目组这边的要求,我才重新看清了单元测试的重要性,请听我娓娓道来~
单元测试究竟能干嘛
单元测试究竟能干嘛这个问题时常疑惑着我,毕竟很多时候都是一个人从零到一进行开发或者接收项目能有好同事👋手把手教导,能大概了解整个项目的运行过程,直到我来到了一个用 AI 来生成业务的一个项目组里面,一切都发生了改变🌱。
我总结了单元测试的几点好处🔽:
-
能帮助接手项目的人快速了解项目的流程。
这点真的很重要,我新接手项目的时候,就只有同事简单的说了几句话,我甚至只能知道这项目是 AI 提问回答流程,然后我直接懵逼,不过通过单元测试,我一步步看来下,倒是能大概了解了项目整体的逻辑。
-
降低代码出错的概率。
每次在原有接口进行了一系列改动,在没有单元测试之前都要自己去接口文档手动尝试,甚至引来了测试一大堆指责。在使用单元测试之后,新增完的代码逻辑,直接新增对应功能的单元测试,直接全部执行,如果都能通过,这代码出问题的概率将会大大减少
-
不用担心影响数据库的数据。
运行单元测试对于很多环境配置都可以直接使用独立的数据库,比如说 MySQL 的数据可以使用 H2 数据库,而 Redis 又可以使用 RedisServer 来创建。
单元测试的小技巧
对于单元测试,我总结了一些我自己使用中的小技巧,这些小技巧的使用往往能有奇效!
抽象测试类
@SpringBootTest(classes = { Application.class, },webEnvironment = SpringBootTest.WebEnvironment.MOCK,properties = {"spring.profiles.active=test"}
)
@Slf4j
@AutoConfigureMockMvc
public abstract class TestBase {
protected static final Long TEST_GROUP_ID = 1L;
@Autowiredprotected MockMvc mockMvc;
}
这个测试类直接打上了需要使用的注解,后续使用直接继承即可,不用每次写上繁琐的注解,示例代码如下:
class Test extends TestBase {}
在 Spring 项目中使用 H2 代替 MySQL
- 引入 H2 依赖
<dependency><groupId>com.h2database</groupId><artifactId>h2</artifactId><scope>runtime</scope></dependency>
- 通过 application-test.yml 来配置 H2 数据源
spring:datasource:driver-class-name: org.h2.Driverschema: classpath:db/schema.sql #H2 数据库的建表语句data: classpath:db/data.sql #H2 数据库的插入数据语句url: jdbc:h2:mem:test #H2 数据库的默认连接地址username: testpassword: test
- 完成上面的步骤后,H2 数据库其实就已经替代掉 MySQL 了,但是要注意的是 MySQL 的 sql 语句与 H2 的有一丢丢的差别,语法可能并不适用,分享一个 IDEA 的插件就可以解决这个问题。
在单元测试中使用 Redis
有不少小伙伴总不喜欢在本地启动一个 Redis ,那么单元测试有什么解决办法呢!当然有!这就用到了 embedded-redis 的一个库,使用超级简单。
- 引入 embedded-redis 依赖
<dependency><groupId>it.ozimov</groupId><artifactId>embedded-redis</artifactId><version>0.7.3</version><scope>test</scope><!-- 不排除掉slf4j的话 会冲突--><exclusions><exclusion><groupId>org.slf4j</groupId><artifactId>slf4j-simple</artifactId></exclusion></exclusions></dependency>
- 直接在单元测试中编写
private static RedisServer redisServer;@BeforeAllpublic static void beforeAll() {redisServer = RedisServer.builder().setting("maxheap 200m").port(6379).build();redisServer.start();}
Spring 单元测试 mock 数据
在我最近接收这个项目中调用 AI 花费是十分昂贵的,总不能单元每次都要调用 AI,不仅烧钱而且还有不确定性。有些需要 mock 的数据就可以使用 Mockito 这个强大的库来进行操作。
- 引入依赖(虽然说 SpringBoot 中会自带,但有时候我嫌弃他的版本不够高,但我又不能改 SpringBoot 依赖,就使用了覆盖)。
<dependency><groupId>org.mockito</groupId><artifactId>mockito-core</artifactId><scope>test</scope></dependency><dependency><groupId>org.mockito</groupId><artifactId>mockito-inline</artifactId><version>3.12.4</version><scope>test</scope></dependency><dependency><groupId>org.mockito</groupId><artifactId>mockito-junit-jupiter</artifactId><version>3.12.4</version><scope>test</scope></dependency>
-
mock 要代理的服务。
举个例子我要 mock 一个类的方法,首先可以直接使用
@MockBean
注解来代理,这个注解跟@Autowired
注解类似,也是让代理创建。接着就是让单元测试执行前,先将这个 Spring 代理对象 mock 创建它,给他指定返回的数据内容。示例代码如下:
@MockBeanprivate TestAgent testAgent;@BeforeEachpublic void beforeEach() {Mockito.when(testAgent.answer(any(), any())).thenAnswer(invocation -> {return "预期结果"});}
这里有几个注意的点:
1==> 这里的 any() 就是对应的输入任何数据,都要返回这个预期结果,其他的还可以自定义。
2==> 这里的代理只能返回一条数据或者里面自定义规则来返回不同数据,如果要每次都按顺序返回可以使用另一种方法 SideEffect 。
- 使用 SideEffect 来进行 mock 返回。
跟上面直接流程一样,但是不一样的是 thenAnswer
的后续处理,输入是一个 List 里面会按 List 内容的顺序依次返回。示例代码如下:
List<String> list = new ArrayList();list.add("聪1");list.add("聪2");list.add("聪3");Mockito.when(testAgent.answer(Mockito.any(), Mockito.any())).thenAnswer(new SideEffect<>(list));
不想启动 Spring 容器
不想启动 Spring 容器,但是代码中用到了 Spring 的代理,SpringBoot 容器的启动十分的慢对于我的电脑,但是我要进行单元测试的部分其实并不涉及 Spring ,我直接进行 AI 请求访问而已,接着就可以使用我以下的方法,直接启动。
-
在单元测试中有移除 Spring 相关注解。
移除掉注解后,在类上面打上
@ExtendWith(MockitoExtension.class)
注解,示例代码如下:
@ExtendWith(MockitoExtension.class)class Test {....}
-
对于交由 Spring 创建的对象进行手动创建。
示例代码如下:
// 不用使用注解private TestAgent testAgent;@BeforeEachvoid setUp() {testAgent = new TestAgent();}
- 后面直接使用对象直接请求即可。
最后
我想我大抵是疯了,我喜欢上了写单元测试,单元测试写完根本停不下来,再未来我会总结更多的单元测试小方法,如果你们有自己总结的一些关于单元测试的方法,欢迎大家一起分享学习~ 最后最后!我是聪希望可以跟大家一起学习,我的 Github:github.com/lhccong 如果里面有你感兴趣的项目不妨给我点个星星⭐和关注🔥,未来我还会持续写新的好玩的小项目。
相关文章:

我想我大抵是疯了,我喜欢上了写单元测试
前言 大家好我是聪。相信有不少的小伙伴喜欢写代码,但是对于单元测试这些反而觉得多此一举,想着我都在接口文档测过了!还要写什么单元测试!写不了一点!! 由于本人也是一个小小程序猿🙉…...

【Visual Studio】Visual Studio使用技巧及报错解决合集
目录 目录 一.概述 二.Visual Studio报错问题及解决方法 三.Visual Studio操作过程中遇到的问题及解决方法 四.Visual Studio编译优化选项 五.Visual Studio快捷键 一.概述 持续更新Visual Studio报错及解决方法,包括Visual Studio报错问题及解决方法、Visua…...

服务器数据恢复—raid5阵列热备盘同步失败导致lun不可用的数据恢复案例
服务器存储数据恢复环境: 华为S5300存储中有一组由16块FC硬盘组建的RAID5磁盘阵列(包含一块热备盘)。 服务器存储故障: 该存储中的RAID5阵列1块硬盘由于未知原因离线,热备盘上线并开始同步数据,数据同步到…...

算法题目整合
文章目录 121. 小红的区间翻转142. 两个字符串的最小 ASCII 删除总和143. 最长同值路径139.完美数140. 可爱串141. 好二叉树 121. 小红的区间翻转 小红拿到了两个长度为 n 的数组 a 和 b,她仅可以执行一次以下翻转操作:选择a数组中的一个区间[i, j]&…...

万界星空科技AI低代码平台:重塑数字化创新边界
在这个日新月异的数字化时代,技术的飞速发展正以前所未有的力量重塑着每一个行业。企业如何在瞬息万变的市场环境中保持竞争力,实现业务的快速迭代与创新? 重塑开发模式,加速数字化转型 传统软件开发周期长、成本高、门槛高&…...

iredmail服务器安装步骤详解!如何做配置?
iredmail服务器安全性设置指南?怎么升级邮件服务器? iredmail是一个功能强大的邮件服务器解决方案,它集成了多个开源软件,使您能够快速部署和管理邮件服务。AokSend将逐步引导您完成安装过程,无需深入的编程知识即可轻…...
【vue深入学习第1章】Vue.js 中的 Ajax 处理:vue-resource 库的深度解析
在现代前端开发中,Ajax 请求是与后端进行数据交互的关键技术。Vue.js 作为一个渐进式 JavaScript 框架,提供了多种方式来处理 Ajax 请求,其中 vue-resource 是一个较为常用的库。尽管 vue-resource 在 Vue 2.x 之后不再是官方推荐的 Ajax 处理…...

JDK新特性(Lambda表达式,Stream流)
Lambda表达式: Lambda 表达式背后的思想是函数式编程(Functional Programming)思想。在传统的面向对象编程中,程序主要由对象和对象之间的交互(方法调用)构成;而在函数式编程中,重点…...

【ARM】MDK-服务器与客户端不同网段内出现卡顿问题
【更多软件使用问题请点击亿道电子官方网站】 1、 文档目标 记录不同网段之间的请求发送情况以及MDK网络版license文件内设置的影响。 2、 问题场景 客户使用很久的MDK网络版,在获取授权时都会出现4-7秒的卡顿,无法对keil进行任何操作,彻底…...

c++树(一)定义,遍历
目录 树的定义 树的基本术语 树的初始起点:我们定义为根 树的层次: 树的定义: 树的性质 性质1: 性质2: 树形结构存储的两种思路 树的遍历模板 树上信息统计方式1-自顶向下统计 树上信息统计方式2-自底向上统…...

YOLOv5和LPRNet的车牌识别系统
车牌识别系统 YOLOv5和LPRNet的车牌识别系统结合了深度学习技术的先进车牌识别解决方案。该系统整合了YOLOv5目标检测框架和LPRNet文本识别模型 1. YOLOv5目标检测框架 YOLO是一种先进的目标检测算法,以其实时性能和高精度闻名。YOLOv5是在前几代基础上进行优化的…...

内容安全(深度行为检测技术、IPS、AV、入侵检测方法)
1、深度行为检测技术 深度行为检测技术:是一种基于深度学习和机器学习的技术,它通过分析用户在网络中的行为模式,识别异常或潜在威胁行为,从而保护网络安全和内容安全 分类: 深度包检测技术(Deep Packet…...

MySQL双主双从实现方式
双主双从(MM-SS) 前言 避免单一主服务器宕机,集群写入能力缺失 从 1 复制 主1 ,从 2 复制 主 2 主 1 复制 主 2,主 2 复制主 1 也就是 主 1 和主 2 互为主从。主1主2互为主从, 是为了以下情景,…...

pico+unity手柄和摄像机控制初级设置
1、摄像头配置 摄像头模式、floor是追踪原点类型(将根据设备检测到地面的高度来计算追踪原点), Device 模式时,为通常理解的 Eye 模式,不会将根据设备检测到地面的高度来计算追踪原点 选择floor时,修改相…...

vxe-grid 实现配置式form搜索条件 form搜索条件框可折叠 配置式table
文章目录 效果图代码 效果图 代码 <template><div class"app-container"><vxe-grid refxGrid v-bind"gridOptions" v-if"tableHeight" :height"tableHeight"><template #billDate"{ data }"><e…...
TS相较于JS有什么优缺点
TypeScript(TS)是JavaScript的一个超集,它添加了静态类型检查和编译时的强大功能,目的是提高代码质量和维护性。相较于JavaScript,TS的主要优点和缺点如下: 优点: 类型安全性:通过…...

【Harmony】SCU暑期实训鸿蒙开发学习日记Day2
目录 Git 参考文章 常用操作 ArkTS的网络编程 Http编程 发送请求 GET POST 处理响应 JSON数据解析 处理响应头 错误处理 Web组件 用生命周期钩子实现登录验证功能 思路 代码示例 解读 纯记录学习日记,杂乱,误点的师傅可以掉了…...

vue3前端开发-执行npm run dev提示报错怎么解决
vue3前端开发-执行npm run dev提示报错怎么解决!今天在本地安装初始化了一个vue3的案例demo。但是当我执行npm run dev想启动它时报错了说,找不到dev。让我检查package.json文件是否包含dev。如下图所示: 实际上,不必惊慌…...
https 单向认证和双向认证
单向认证 单向认证是客户端(通常是浏览器)验证服务器的身份。服务器向客户端提供数字证书,客户端通过验证该证书的真实性来确认与服务器的连接是安全的。 服务器提供证书:服务器向客户端提供一个数字证书,用于验证服务器的身份。客户端验证服务器:客户端验证服务器的证书…...
Python中Selenium 和 keyboard 库的使用
文章目录 一、Selenium基本使用2.等待元素加载常用操作 keyboard基本使用与 Selenium 联合使用 一、Selenium Selenium 是一个用于浏览器自动化的工具。它可以模拟用户与网页的交互,如点击按钮、填写表单、导航页面等。Selenium 支持多种编程语言,包括 …...

C++实现分布式网络通信框架RPC(3)--rpc调用端
目录 一、前言 二、UserServiceRpc_Stub 三、 CallMethod方法的重写 头文件 实现 四、rpc调用端的调用 实现 五、 google::protobuf::RpcController *controller 头文件 实现 六、总结 一、前言 在前边的文章中,我们已经大致实现了rpc服务端的各项功能代…...

Linux 文件类型,目录与路径,文件与目录管理
文件类型 后面的字符表示文件类型标志 普通文件:-(纯文本文件,二进制文件,数据格式文件) 如文本文件、图片、程序文件等。 目录文件:d(directory) 用来存放其他文件或子目录。 设备…...

基于FPGA的PID算法学习———实现PID比例控制算法
基于FPGA的PID算法学习 前言一、PID算法分析二、PID仿真分析1. PID代码2.PI代码3.P代码4.顶层5.测试文件6.仿真波形 总结 前言 学习内容:参考网站: PID算法控制 PID即:Proportional(比例)、Integral(积分&…...
逻辑回归:给不确定性划界的分类大师
想象你是一名医生。面对患者的检查报告(肿瘤大小、血液指标),你需要做出一个**决定性判断**:恶性还是良性?这种“非黑即白”的抉择,正是**逻辑回归(Logistic Regression)** 的战场&a…...

dedecms 织梦自定义表单留言增加ajax验证码功能
增加ajax功能模块,用户不点击提交按钮,只要输入框失去焦点,就会提前提示验证码是否正确。 一,模板上增加验证码 <input name"vdcode"id"vdcode" placeholder"请输入验证码" type"text&quo…...

基于Docker Compose部署Java微服务项目
一. 创建根项目 根项目(父项目)主要用于依赖管理 一些需要注意的点: 打包方式需要为 pom<modules>里需要注册子模块不要引入maven的打包插件,否则打包时会出问题 <?xml version"1.0" encoding"UTF-8…...

CMake 从 GitHub 下载第三方库并使用
有时我们希望直接使用 GitHub 上的开源库,而不想手动下载、编译和安装。 可以利用 CMake 提供的 FetchContent 模块来实现自动下载、构建和链接第三方库。 FetchContent 命令官方文档✅ 示例代码 我们将以 fmt 这个流行的格式化库为例,演示如何: 使用 FetchContent 从 GitH…...
Web 架构之 CDN 加速原理与落地实践
文章目录 一、思维导图二、正文内容(一)CDN 基础概念1. 定义2. 组成部分 (二)CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 (三)CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 …...
CSS设置元素的宽度根据其内容自动调整
width: fit-content 是 CSS 中的一个属性值,用于设置元素的宽度根据其内容自动调整,确保宽度刚好容纳内容而不会超出。 效果对比 默认情况(width: auto): 块级元素(如 <div>)会占满父容器…...

uniapp 开发ios, xcode 提交app store connect 和 testflight内测
uniapp 中配置 配置manifest 文档:manifest.json 应用配置 | uni-app官网 hbuilderx中本地打包 下载IOS最新SDK 开发环境 | uni小程序SDK hbulderx 版本号:4.66 对应的sdk版本 4.66 两者必须一致 本地打包的资源导入到SDK 导入资源 | uni小程序SDK …...