单测的思路
文章目录
- 单测的定义
- 方法的单测
- 几种生成工具的对比
- 生成步骤
- 接口的单测
- 场景的单测
- 总结
- 参考
单测的定义
- 单元测试(Unit Testing)是一种软件开发中的测试方法,它的主要目的是确保软件中的最小可测试单元(通常是函数、方法或类)在被单独测试和验证时能够按照预期工作。尽管单元测试有很多优点,如提高代码质量、减少Bug、简化调试过程等,但它也存在一些缺点:
- 增加开发时间:如要求覆盖率到80%甚至90%,或者入参几十个难以构造,单测时间占比可能超过30%。
- 需要维护:随着代码的改变,特别是大规模的重构,单元测试也需要相应地更新和维护,增加开发的负担。
- 无法发现对其他类的影响:单元测试主要关注单个单元的行为,无法发现与多个单元交互或整个系统相关的问题。
- 所以部分公司会要求写接口维度、场景维度的单测,覆盖率在50-60%,甚至不强制要求覆盖率。
方法的单测
推荐用更智能的squaretest生成单测模板后,手工调整。
几种生成工具的对比
- diffblue
- 优点:
- 与IntelliJ IDEA集成良好,使用方便。
- 支持多种编程语言和框架。
- 缺点:
- 商用版本收费较高,对于个人用户或小型团队可能不太友好。
- 在处理某些特定写法或框架时可能不够灵活。
- 优点:
- squaretest
- 优点:
- 生成测试用例,自动覆盖部分if分支,减轻测试负担。
- 缺点:
- 只有30天的免费试用期,之后需要付费使用。事实上点掉remind后可以继续使用。
- 没有社区版支持,对于开源项目或个人用户可能不太友好。
- 优点:
- EvoSuite
- 优点:
- 作为Maven插件使用,方便集成到Java项目中。
- 支持生成多样化的测试用例,有助于发现潜在的缺陷。
- 缺点:
- 社区支持相对较少,遇到问题时可能难以得到及时帮助。
- 配置和使用可能相对复杂,需要一定的学习成本。
- 在处理某些特定场景或框架时可能不够灵活或有效。
- 优点:
- TestMe
- 优点:
- 简单易用,适合初学者或小型项目使用。
- 缺点:
- 需要手动填充输入参数和逻辑,自动化程度较低。
- 生成的测试用例可能不够全面或深入,需要额外补充和完善。
- 优点:
生成步骤
-
安装插件

-
引入依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><version>2.1.1.RELEASE</version></dependency><dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter</artifactId><version>5.8.2</version></dependency>
- 编写业务代码
@Service
public class TestServiceImpl implements TestService {@Resourceprivate TestRepository testRepository;@Resourceprivate TestThird testThird;@Overridepublic void start(InputDTO inputDTO) {InputEntity entity = testRepository.select(inputDTO.getId());if (entity == null) {testRepository.insert(entity = new InputEntity());}testThird.callThird(entity);}
}
- 生成单测


- 单测生成结果
/*** squaretest*/
class TestServiceImplTest {@Mockprivate TestRepository mockTestRepository;@Mockprivate TestThird mockTestThird;@InjectMocksprivate TestServiceImpl testServiceImplUnderTest;@BeforeEachvoid setUp() {initMocks(this);}@Testvoid testStart() {// Setupfinal InputDTO inputDTO = new InputDTO();inputDTO.setName("name");inputDTO.setId(0);final InputDetail inputDetail = new InputDetail();inputDetail.setName("name");inputDTO.setInputDetail(inputDetail);// Configure TestRepository.select(...).final InputEntity inputEntity = new InputEntity();inputEntity.setId(0);inputEntity.setName("name");when(mockTestRepository.select(0)).thenReturn(inputEntity);when(mockTestRepository.insert(any(InputEntity.class))).thenReturn(0);// Run the testtestServiceImplUnderTest.start(inputDTO);// Verify the resultsverify(mockTestRepository).insert(any(InputEntity.class));verify(mockTestThird).callThird(any(InputEntity.class));}
}
/*** testme*/
class TestServiceImplTestTestMe {@MockTestRepository testRepository;@MockTestThird testThird;@InjectMocksTestServiceImpl testServiceImpl;@BeforeEachvoid setUp() {MockitoAnnotations.initMocks(this);}@Testvoid testStart() {when(testRepository.select(anyInt())).thenReturn(new InputEntity());when(testRepository.insert(any())).thenReturn(Integer.valueOf(0));testServiceImpl.start(new InputDTO());}
}
接口的单测
mock外部依赖,启动容器,调用接口
- 编写外部依赖的mock类
@Service
public class TestThirdImpl implements TestThird {@Overridepublic void callThird(InputEntity entity) {System.out.println("TestThirdImpl callThird");}
}
//mock
public class TestThirdMockImpl implements TestThird {public void callThird(InputEntity entity) {System.out.println("TestThirdMockImpl callThird");}
}
- 替换容器中的bean,mock外部依赖
@Configuration
public class MockConfig {@Beanpublic BeanDefinitionRegistryPostProcessor beanDefinitionRegistryPostProcessor() {return new BeanDefinitionRegistryPostProcessor() {@Overridepublic void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {//移除依赖的beanregistry.removeBeanDefinition("testThirdImpl");//获取Mockbean的定义BeanDefinition beanDe = BeanDefinitionBuilder.rootBeanDefinition(TestThirdMockImpl.class).getBeanDefinition();//注册mockbeanregistry.registerBeanDefinition("testThirdImpl", beanDe);}@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {}};}
}
- test模块中启动容器,并调用入口方法
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = TestApplication.class)
public class TestApplicationTest {@Resourceprivate TestService testService;@Testpublic void start() {testService.start(new InputDTO());}}
场景的单测
将接口单测组合
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = TestApplication.class)
public class TestApplicationTest {@Resourceprivate TestService testService;@Testpublic void start() {testService.start(new InputDTO());testService.end(new InputDTO());}}
总结
- 方法的单测:覆盖入参少、业务分支多的场景。
- 接口、场景的单测:覆盖主干流程。
参考
- 告别加班/解放双手提高单测覆盖率之Java 自动生成单测代码神器推荐
- JUnit 5 User Guide
- 关于testNG和JUnit的对比
- JUnit 5 单元测试教程
- 单元测试自动生成工具EvoSuite的简单使用
- 使用BeanDefinitionRegistryPostProcessor动态注入BeanDefinition
相关文章:
单测的思路
文章目录 单测的定义方法的单测几种生成工具的对比生成步骤 接口的单测场景的单测总结参考 单测的定义 单元测试(Unit Testing)是一种软件开发中的测试方法,它的主要目的是确保软件中的最小可测试单元(通常是函数、方法或类&…...
Linux内核与驱动面试经典“小”问题集锦(6)
接前一篇文章:Linux内核与驱动面试经典“小”问题集锦(5) 问题8 问:如何判断一个数是否是2的幂次(假设最多32位)? 备注:此问题是笔者年前参加小米面试时遇到的一个问题,…...
【zabbix】(四)-钉钉告警企业微信配置
前提条件: 已经安装了Python3环境(脚本需要requests模块)。Centos7.x自带Python2(不含requests模块) 钉钉告警配置 一 安装Python3 参考该优秀文档部署 查看Python的模块:pip list / pip3 list 报错 …...
python-自动化篇-办公-一键将word中的表格提取到excel文件中
文章目录 代码 工作中,经常需要将Word文档中的表格粘贴到Excel文件中,以便汇总及分析。一个一个复制粘贴,非常不方便,还是Python自动化操作,省心省力。要求如下图所示,即将word中的所有表格,转存…...
C#,数值计算,矩阵的行列式(Determinant)、伴随矩阵(Adjoint)与逆矩阵(Inverse)的算法与源代码
本文发布矩阵(Matrix)的一些初级算法。 一、矩阵的行列式(Determinant) 矩阵行列式是指矩阵的全部元素构成的行列式,设A(a)是数域P上的一个n阶矩阵,则所有A(a)中的元素组成的行列式称为矩阵A的行列式&…...
人工智能|推荐系统——基于tensorflow的个性化电影推荐系统实战(有前端)
代码下载: 基于tensorflow的个性化电影推荐系统实战(有前端).zip资源-CSDN文库 项目简介: dl_re_web : Web 项目的文件夹re_sys: Web app model:百度云下载之后,把model放到该文件夹下recommend: 网络模型相…...
Hive SQL编译成MapReduce任务的过程
目录 一、架构及组件介绍 1.1 Hive底层架构 1.2 Hive组件 1.3 Hive与Hadoop交互过程 二、Hive SQL 编译成MR任务的流程 2.1 HQL转换为MR源码整体流程介绍 2.2 程序入口—CliDriver 2.3 HQL编译成MR任务的详细过程—Driver 2.3.1 将HQL语句转换成AST抽象语法树 词法、语…...
【C++】快速上手map、multimap、set、multiset
文章目录 一、前言二、set / multiset1. 常见应用2. 核心操作 三、map / multimap1. 常见应用2. 核心操作 一、前言 S T L STL STL 中的关联式容器分为树型结构和哈希结构,树型结构主要有四种: s e t set set、 m u l t i s e t multiset multiset、 m a…...
【分享】图解ADS+JLINK调试ARM
文章是对LPC2148而写的,但是对三星的44B0芯片同样适用,只需要在选择时将相应的CPU选择的S3C44B0就可以了。 JLINK在ADS下调试心得 前两天一个客户用jlink在ADS下调试LPC2148总报错,这个错误我之前在调试LPC2200的时候也碰到过,后…...
反无人机系统技术分析,无人机反制技术理论基础,无人机技术详解
近年来,经过大疆、parrot、3d robotics等公司不断的努力,具有强大功能的消费级无人机价格不断降低,操作简便性不断提高,无人机正快速地从尖端的军用设备转入大众市场,成为普通民众手中的玩具。 然而,随着消…...
Kotlin和Java 单例模式
Java 和Kotlin的单例模式其实很像,只是Kotlin一部分单例可以用对象类和委托lazy来实现 Java /*** 懒汉式,线程不安全*/ class Singleton {private static Singleton instance;private Singleton() {}public static Singleton getInstance() {if (insta…...
软考 系统分析师系列知识点之信息系统战略规划方法(9)
接前一篇文章:软考 系统分析师系列知识点之信息系统战略规划方法(8) 所属章节: 第7章. 企业信息化战略与实施 第4节. 信息系统战略规划方法 7.4.5 信息工程方法 信息工程(Information Engineering,IE&…...
政安晨:示例演绎TensorFlow的官方指南(一){基础知识}
为什么要示例演绎? 既然有了官方指南,咱们在官方指南上看看就可以了,为什么还要写示例演绎的文章呢? 其实对于初步了解TensorFlow的小伙伴们而言,示例演绎才是最重要的。 官方文档已经假定了您已经具备了相当合适的…...
node - 与数据库交互
在Web开发中,与数据库交互是常见的需求,用于持久化存储、检索和操作数据。不同的后端技术和数据库类型(如关系型数据库和非关系型数据库)有着不同的交互方式。下面介绍几种常见的数据库交互方法。 关系型数据库 关系型数据库(如MySQL、PostgreSQL、SQLite)使用结构化查…...
速盾:2024年cdn在5g时代重要吗
在2024年,随着5G技术的普及与应用,内容分发网络(Content Delivery Network,CDN)在数字化时代中的重要性将进一步巩固和扩大。CDN是一种用于快速、高效地分发网络内容的基础设施,它通过将内容部署在全球各地…...
微信小程序(四十一)wechat-http的使用
注释很详细,直接上代码 上一篇 新增内容: 1.模块下载 2.模块的使用 在终端输入npm install wechat-http 没有安装成功vue的先看之前的一篇 微信小程序(二十)Vant组件库的配置- 如果按以上的成功配置出现如下报错先输入以下语句 …...
所有设计模式大全及学习链接
文章目录 创建型设计模式结构型设计模式行为型设计模式 创建型设计模式 一种创建对象的设计模式,它们提供了一种灵活的方式来创建对象,同时隐藏了对象的创建细节。以下是常见的创建型设计模式: 工厂方法模式(Factory Method Patte…...
【Java程序设计】【C00264】基于Springboot的原创歌曲分享平台(有论文)
基于Springboot的原创歌曲分享平台(有论文) 项目简介项目获取开发环境项目技术运行截图 项目简介 这是一个基于Springboot的原创歌曲分享平台 本系统分为平台功能模块、管理员功能模块以及用户功能模块。 平台功能模块:在平台首页可以查看首…...
2024年,要特别注意这两个方位
家居风水对每个家庭都非常重要,可在无形中影响到人们的事业、财富以及健康运势。俗话说:“风水轮流转”,2024年为甲辰龙年,斗转星移、九宫飞星将改变宫位,新一年的磁场即将启动,方位的吉凶也会重新变动&…...
【Chrono Engine学习总结】5-sensor-5.1-sensor基础并创建一个lidar
由于Chrono的官方教程在一些细节方面解释的并不清楚,自己做了一些尝试,做学习总结。 1、Sensor模块 Sensor模块是附加模块,需要单独安装。参考:【Chrono Engine学习总结】1-安装配置与程序运行 Sensor Module Tutorial Sensor …...
在软件开发中正确使用MySQL日期时间类型的深度解析
在日常软件开发场景中,时间信息的存储是底层且核心的需求。从金融交易的精确记账时间、用户操作的行为日志,到供应链系统的物流节点时间戳,时间数据的准确性直接决定业务逻辑的可靠性。MySQL作为主流关系型数据库,其日期时间类型的…...
Debian系统简介
目录 Debian系统介绍 Debian版本介绍 Debian软件源介绍 软件包管理工具dpkg dpkg核心指令详解 安装软件包 卸载软件包 查询软件包状态 验证软件包完整性 手动处理依赖关系 dpkg vs apt Debian系统介绍 Debian 和 Ubuntu 都是基于 Debian内核 的 Linux 发行版ÿ…...
【C++从零实现Json-Rpc框架】第六弹 —— 服务端模块划分
一、项目背景回顾 前五弹完成了Json-Rpc协议解析、请求处理、客户端调用等基础模块搭建。 本弹重点聚焦于服务端的模块划分与架构设计,提升代码结构的可维护性与扩展性。 二、服务端模块设计目标 高内聚低耦合:各模块职责清晰,便于独立开发…...
selenium学习实战【Python爬虫】
selenium学习实战【Python爬虫】 文章目录 selenium学习实战【Python爬虫】一、声明二、学习目标三、安装依赖3.1 安装selenium库3.2 安装浏览器驱动3.2.1 查看Edge版本3.2.2 驱动安装 四、代码讲解4.1 配置浏览器4.2 加载更多4.3 寻找内容4.4 完整代码 五、报告文件爬取5.1 提…...
算法笔记2
1.字符串拼接最好用StringBuilder,不用String 2.创建List<>类型的数组并创建内存 List arr[] new ArrayList[26]; Arrays.setAll(arr, i -> new ArrayList<>()); 3.去掉首尾空格...
PAN/FPN
import torch import torch.nn as nn import torch.nn.functional as F import mathclass LowResQueryHighResKVAttention(nn.Module):"""方案 1: 低分辨率特征 (Query) 查询高分辨率特征 (Key, Value).输出分辨率与低分辨率输入相同。"""def __…...
现有的 Redis 分布式锁库(如 Redisson)提供了哪些便利?
现有的 Redis 分布式锁库(如 Redisson)相比于开发者自己基于 Redis 命令(如 SETNX, EXPIRE, DEL)手动实现分布式锁,提供了巨大的便利性和健壮性。主要体现在以下几个方面: 原子性保证 (Atomicity)ÿ…...
Vite中定义@软链接
在webpack中可以直接通过符号表示src路径,但是vite中默认不可以。 如何实现: vite中提供了resolve.alias:通过别名在指向一个具体的路径 在vite.config.js中 import { join } from pathexport default defineConfig({plugins: [vue()],//…...
Linux系统部署KES
1、安装准备 1.版本说明V008R006C009B0014 V008:是version产品的大版本。 R006:是release产品特性版本。 C009:是通用版 B0014:是build开发过程中的构建版本2.硬件要求 #安全版和企业版 内存:1GB 以上 硬盘…...
MySQL 主从同步异常处理
阅读原文:https://www.xiaozaoshu.top/articles/mysql-m-s-update-pk MySQL 做双主,遇到的这个错误: Could not execute Update_rows event on table ... Error_code: 1032是 MySQL 主从复制时的经典错误之一,通常表示ÿ…...
