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

什么是优秀的单元测试?

阅读本文之前,请投票支持这款 全新设计的脚手架 ,让 Java 再次伟大!

单元测试的质量意义

合理编写单元测试,可使团队工程师告别牛仔式编程,产出易维护的高质量代码。随着单元测试覆盖率的上升,项目会更加的健壮,团队的信心满满,充满斗志。

无论是瀑布团队还是敏捷团队,单元测试及自动化单元测试作为重要的质量保证手段的价值已经被大家接纳与认可。

但是,对于大多数团队来讲当测试覆盖率提升一定阶段后,收益会迎来瓶颈。

单元测试的设计意义

单元测试除了作为质量保证手段以外,更应该作为设计手段。TDD 的核心思想之一,就是使用单元测试作为设计手段,使开发者在编写测试用例时,以调用者的思维方式来写代码,这种方式的收益会比作为保护手段更高。
利用测试驱动开发可以让你的设计更加优良、编写出可测试的代码、还能避免在不切实际的假设上过度设计系统。

优秀测试的共性

  1. 良好的测试代码具备可读性和可维护性。
  2. 测试代码在项目中有结构化的组织方式。
  3. 测试具备可靠性和可重复性。
  4. 合理的使用测试替身。
  5. AAA(Arrange, Act & Assert)——准备、执行、断言。 编写测试代码时,使用被称为三A模型:准备、执行、断言。

测试替身(test double)

为了方便的测试代码以及绕开各种环境限制,应该使用替身来代替真实对象。

public class Car {// 对外封闭的引擎对象。你无法知道内在信息。private Engine engine;public Car(Engine engine) {this.engine = engine;}// 需要测试的启动功能public void start() {engine.start();}// 需要测试汽车的驾驶功能public void drive(Route route) {// 根据路线状态获取提供给 car 使用的各种方向 (十分复杂的算法,初始化时需要涉及 gis 算法。最终获取的对对象与当前的时间有关)for (Directions directions : route.getDirections()) {directions.follow();}}}

为了验证一段代码的行为符合你的期望,最好的选择是替换其周围的代码,使你获得对环境的完整控制。使用了替身,能让执行速度变得更快,并且可以随意模拟特殊情况。


public class TestRoute extends Route {// 伪造的替身实现了快速返回路线以及返回固定路线的方法,使测试具备了可靠与可重复性@Overridepublic List<Directions> getDirections() {System.out.println("快速的返回固定的路线");return new ArrayList<Directions>();}}public class TestEngine extends Engine {private boolean engineFlg = false;@Overridepublic void start() {engineFlg = true;}@Overridepublic void stop() {engineFlg = false;}public boolean isEngineFlg() {return engineFlg;}public void setEngineFlg(boolean engineFlg) {this.engineFlg = engineFlg;}}

使用替身替换协作者,隔离被测代码意味着将需要测试的代码与其他代码隔离开来。

    @Testpublic void testCarStart() {TestEngine engine = new TestEngine();new Car(engine).start();assertTrue(engine.isEngineFlg());}@Testpublic void testCarDrive() {TestRoute testRoute = new TestRoute();TestEngine engine = new TestEngine();new Car(engine).drive(testRoute);}

测试替身的类型

替身拥有多种类型。不同的测试场景选择合理的测试替身是优秀测试的必要条件之一。测试替身的类型也决定了测试类的命名方法,尤其特别注意。

桩(stub)

用最简单的可能实现来代替真实实现。桩总是短小的。最好的例子就是一个对象的所有方法都只有一行,并且返回一个默认值。

public class LoggerStub implements Logger {@Overridepublic void log() {// Nope}
}
伪造对象 (fake)

有时,我们至少需要填充一些行为,而有时候你需要测试替身根据收到的消息种类来表现出不同的行为。
Fake 就像是真实事物的简单版本,他能够伪造真实事物的行为,具备简单的业务逻辑,同时没有副作用或者使用真实事物的其他后果。

    public class TestRoute extends Route {// 伪造的替身实现了快速返回路线以及返回固定路线的方法,使测试具备了可靠与可重复性@Overridepublic List<Directions> getDirections() {System.out.println("快速的返回固定的路线");return new ArrayList<Directions>();}}

伪造对象与测试桩十分常用,你可以在测试时用它们替换掉缓慢的真实事物,以及鞭长莫及的依赖。

测试间谍 (spy)

测试间谍用于记录你和某个不对你开放的对象之间的交互。当对象与协作者之间交互时,无法获取协作者交互结果的情况下,会使用测试间谍。

// 测试间谍public class TestEngine extends Engine {// 对外暴露信息private boolean engineFlg = false;// 比真实对象的 start 方法更具有交互性的方法。@Overridepublic void start() {engineFlg = true;}@Overridepublic void stop() {engineFlg = false;}// 对外提供用于获取交互结果的接口,用于断言。public boolean isEngineFlg() {return engineFlg;}public void setEngineFlg(boolean engineFlg) {this.engineFlg = engineFlg;}}
模拟对象 mock

模拟对象是在一个特定情境下可配置行为的对象。模拟对象时一种更加高级与特殊的测试间谍,它关注的重点是两个对象之间的交互行为。

public void mockTest(){final Internet internet = context.mock(Internet.class);context.checking(new Expectations() {{one(internet).get(with(containsString("langpair=en")));will(returnValue("ok"))}};Translator t = new Translator(internet);String translation = t.translate("flower",ENGLISH);assertEquals("ok",translation)}

通过使用模拟对象的预测返回值行为,我们可以更加精确的对交互行为进行验证。

如何选择合适的替身类型

  • 如果你测试的重点是交互,即两个对象之前的调用,你可能需要一个模拟对象 mock。
  • 如果你决定使用 Mock ,但测试代码最终看起来不像你想象的那么漂亮了,则考虑使用 Spy。
  • 如果你只关心协作对象向被测对象输送的响应,用 stub 解决问题。
  • 如果你运行的是一个复杂场景,其中它所依赖的服务无法供测试使用,但是你又需要这些服务提供的行为哪怕是一个简单的提示,那就应该考虑使用 Fake。

相关文章:

什么是优秀的单元测试?

阅读本文之前&#xff0c;请投票支持这款 全新设计的脚手架 &#xff0c;让 Java 再次伟大&#xff01; 单元测试的质量意义 合理编写单元测试&#xff0c;可使团队工程师告别牛仔式编程&#xff0c;产出易维护的高质量代码。随着单元测试覆盖率的上升&#xff0c;项目会更加…...

服务器安装Anaconda,Anaconda安装Pytorch

1.服务器安装Anaconda 1.1 下载Anaconda 在服务器上直接下载 wget https://repo.anaconda.com/archive/Anaconda3-2024.06-1-Linux-x86_64.sh1.2 安装Anaconda bash Anaconda3-2024.06-1-Linux-x86_64.sh然后就显示下面&#xff1a;more 安装过程一直enter即可&#xff0c;…...

YOLO目标检测理论详解,YOLOv1理论知识讲解,超w字精读(学习YOLO框架必备),全网最详细教程

文章目录 前言一、目标检测理论1.目标检测发展史2.目标检测框架理论基础3.本章小结 二、YOLOv1理论知识1.YOLOv1网络结构2.YOLOv1检测原理3.YOLOv1的训练流程&#xff08;1&#xff09;边界框的位置参数&#xff08;2&#xff09;边界框的置信度&#xff08;3&#xff09;类别置…...

SpringBoot3.x和OCR构建车牌识别系统

本专题旨在展示 OCR 技术与 SpringBoot3.x 框架结合的广泛应用。我们会深入探讨它在医疗、金融、教育、交通、零售、公安等多个领域的现实应用。每个应用场景都会提供详细的实例、面临问题的分析与解决策略&#xff0c;以帮助您深入理解 OCR 技术在实践中的关键作用。让我们一同…...

conda 容器学习笔记之一 -- 基础环境配置

1、容器瘦身导致部分应用缺少&#xff0c;需要在非容器环境下部署环境。但为避免破坏现有环境&#xff0c;现有使用conda环境进行隔离管理 创建&#xff1a;conda create -n tts python3.10.0 2、conda 是python环境管理&#xff0c;和python无关的东西比如cann还是会影响 下载…...

Oracle分区表改造(三):通过分区交换和分裂改造为分区表

Oracle分区表改造(三):通过分区交换和分裂改造为分区表 源表数据准备范围分区表改造:非间隔分区创建普通分区表分区交换分区分裂范围分区表改造:间隔分区创建间隔分区表分区交换分区分裂表重命名🐬 创建只有一个分区的分区表, 通过分区交换将原表变成分区表,然后分裂分…...

LeetCode 0908.最小差值 I:思维(遍历)

【LetMeFly】908.最小差值 I&#xff1a;思维&#xff08;遍历&#xff09; 力扣题目链接&#xff1a;https://leetcode.cn/problems/smallest-range-i/ 给你一个整数数组 nums&#xff0c;和一个整数 k 。 在一个操作中&#xff0c;您可以选择 0 < i < nums.length 的…...

Python基础之循环语句

在Python的编程世界里&#xff0c;循环结构犹如一把神奇的钥匙&#xff0c;开启高效处理数据和重复执行任务的大门。它赋予程序员强大的力量&#xff0c;让代码充满活力。Python主要有两种类型的循环语句&#xff1a;for循环和while循环。 一、for循环 for循环通常用于遍历一个…...

项目管理软件真的能让敏捷开发变得更简单吗?

敏捷开发是一种以快速交付和适应变化为核心特点的软件开发方法。其特点包括尽早并持续交付、能够驾驭需求变化、版本周期内尽量不加任务、业务与开发协同工作、以人为核心、团队配置敏捷等。 例如&#xff0c;尽早并持续交付可使用的软件&#xff0c;使客户能够更早地体验产品…...

互联网名称之时间戳

什么是时间戳 时间戳&#xff08;Timestamp&#xff09;是一种用于表示特定时刻的数值或字符串&#xff0c;通常以日期和时间的形式出现。它用于记录某一事件发生的准确时间&#xff0c;在计算机系统中常被用于日志记录、数据处理和同步等场景。 常见的时间戳 在互联网中常见…...

Leetcode—1242. 多线程网页爬虫【中等】Plus(多线程)

2024每日刷题&#xff08;187&#xff09; Leetcode—1242. 多线程网页爬虫 实现代码 /*** // This is the HtmlParsers API interface.* // You should not implement it, or speculate about its implementation* class HtmlParser {* public:* vector<string>…...

RISC-V笔记——内存模型总结

1 前言 Memory consistency model定义了使用Shared memory(共享内存)执行多线程(Multithread)程序所允许的行为规范。RISC-V使用的内存模型是RVWMO(RISC-V Weak Memory Ordering)&#xff0c;RVWMO内存模型是根据全局内存顺序(global memory order)定义的&#xff0c;全局内存…...

后端常用安全措施

一、限流 1.简介 限流就是限制流量&#xff0c;但这里的流量是一个比较笼统的概念。如果考虑各种不同的场景&#xff0c;限流是非常复杂的&#xff0c;而且和具体的业务规则密切相关 通过限流&#xff0c;可以控制服务请求的速率&#xff0c;从而提高系统应对突发大流量的能…...

虚拟机数据恢复—通过拼接数据库页碎片的方式恢复数据库的数据恢复案例

虚拟机数据恢复环境&#xff1a; 某品牌服务器通过同品牌某型号的RAID卡&#xff0c;将4块STAT硬盘为一组RAID10阵列。上层部署XenServer虚拟化平台&#xff0c;虚拟机安装Windows Server系统&#xff0c;每台虚拟机有两个虚拟机磁盘&#xff08;系统盘 数据盘&#xff09;&am…...

【vue】自封组件,基于vue2封装一个弹框组件

源码&#xff1a;https://download.csdn.net/download/galaxyJING/89913551...

ES6基础知识

一、定义变量的关键字let和const 1. let 定义变量的语法&#xff1a; let 变量名 值; 2. 和var定义变量的区别 1. 是否支持同一个作用域变量同名 var支持&#xff0c;let不支持 2. 是否支持预解析 var支持&#xff0c;let不支持 3. 是否会挂载在window对象…...

基于Multisim的模拟拔河游戏比赛设计与仿真

1.设计一个模拟拔河游戏比赛的逻辑电路 2.使用15个发光二极管表示绳子&#xff0c;开机后只有最中间的发光二极管亮。 3.比赛双方各持一个按钮&#xff0c;快速不断地按动按钮&#xff0c;产生脉冲&#xff0c;谁按的快&#xff0c;发光的二极管就向谁的方向移动&#xff0c;每…...

MyBatis 配置详解

在项目中经常会用到 mybatis 相关的一些配置&#xff0c;而在启动类项目工程中&#xff0c;一般会把 mybatis 配置文件单独写到 mybatis,yml 中&#xff0c;如下简单介绍下常用的 mybatis 配置 mybatis:configuration:call-setters-on-nulls: truemap-underscore-to-camel-case…...

研发运营一体化(DevOps)能力成熟度模型

目录 应用设计 安全风险管理 技术运 持续交付 敏捷开发管理 基于微服务的端到端持续交付流水线案例 应用设计 安全风险管理 技术运 持续交付...

躺平成长-利用kimi编辑助手帮助自己编程第二天

天有道&#xff0c;无常道&#xff0c;兵无常势。 {今天开始听歌&#xff08;歌曲&#xff1a;青丝&#xff01;&#xff09;进行编程&#xff01;} 尝试用ai帮助自己进行小程序的开发&#xff0c;同时最为关键&#xff0c;是无法能够完成相关的代码的记忆&#xff0c;所以我开…...

Z-Image-Turbo-辉夜巫女数据预处理实战:模拟VLOOKUP实现提示词与风格模板匹配

Z-Image-Turbo-辉夜巫女数据预处理实战&#xff1a;模拟VLOOKUP实现提示词与风格模板匹配 你有没有遇到过这样的烦恼&#xff1f;每次用AI画图&#xff0c;想生成一个“赛博朋克”风格的图片&#xff0c;都得重新回忆或者翻找之前写好的那一长串复杂的提示词。或者团队里每个人…...

QuickSnap:Blender三维建模效率革命,快速对齐插件让精准建模变得简单

QuickSnap&#xff1a;Blender三维建模效率革命&#xff0c;快速对齐插件让精准建模变得简单 【免费下载链接】quicksnap Blender addon to quickly snap objects/vertices/points to object origins/vertices/points 项目地址: https://gitcode.com/gh_mirrors/qu/quicksnap…...

避坑指南:用高德DistrictSearch获取精准行政边界时遇到的5个典型问题(含最新GeoJson处理技巧)

高德DistrictSearch深度避坑&#xff1a;5个实战难题与GeoJson优化方案 当你在深夜调试地图边界数据时&#xff0c;突然发现某个街道的轮廓出现了诡异的锯齿状变形——这不是恐怖片情节&#xff0c;而是使用高德DistrictSearch时可能遇到的真实场景。作为经历过数十个地图项目…...

如何通过InstantClick事件回调实现精准的性能监控:开发者必备指南

如何通过InstantClick事件回调实现精准的性能监控&#xff1a;开发者必备指南 【免费下载链接】instantclick InstantClick makes following links in your website instant. 项目地址: https://gitcode.com/gh_mirrors/in/instantclick InstantClick是一款能让网站链接…...

Java结构化并发崩溃了?手把手教你用VirtualThread+StructuredTaskScope定位线程泄漏与作用域越界(附JDK21真机调试录屏)

第一章&#xff1a;Java结构化并发崩溃了&#xff1f;手把手教你用VirtualThreadStructuredTaskScope定位线程泄漏与作用域越界&#xff08;附JDK21真机调试录屏&#xff09;Java 21 正式引入结构化并发&#xff08;Structured Concurrency&#xff09;&#xff0c;其核心组件 …...

5步清理60GB重复视频:Krokiet视频查重工具全攻略

5步清理60GB重复视频&#xff1a;Krokiet视频查重工具全攻略 【免费下载链接】czkawka 一款跨平台的重复文件查找工具&#xff0c;可用于清理硬盘中的重复文件、相似图片、零字节文件等。它以高效、易用为特点&#xff0c;帮助用户释放存储空间。 项目地址: https://gitcode.…...

突破限速:8大网盘直链解析方案全解析

突破限速&#xff1a;8大网盘直链解析方案全解析 【免费下载链接】Online-disk-direct-link-download-assistant 可以获取网盘文件真实下载地址。基于【网盘直链下载助手】修改&#xff08;改自6.1.4版本&#xff09; &#xff0c;自用&#xff0c;去推广&#xff0c;无需输入“…...

nli-distilroberta-baseGPU算力优化:显存占用降低37%的DistilRoBERTa推理部署

NLI DistilRoBERTa Base GPU算力优化&#xff1a;显存占用降低37%的推理部署指南 1. 项目概述 自然语言推理(NLI)是理解两段文本之间逻辑关系的重要任务。基于DistilRoBERTa的NLI模型通过知识蒸馏技术&#xff0c;在保持90%以上准确率的同时&#xff0c;模型体积缩小40%&…...

S32K3XX车载以太网驱动:从硬件接口到数据收发的全链路解析

1. S32K3XX车载以太网驱动的硬件架构解析 第一次接触S32K3XX系列芯片的车载以太网驱动时&#xff0c;最让我头疼的就是那一堆专业术语&#xff1a;MAC、PHY、MII、MDIO... 后来在实际项目中摸爬滚打才发现&#xff0c;理解硬件架构就像拆解汽车的发动机&#xff0c;只要搞清各个…...

为什么选择Practical Modern JavaScript:探索ES6未来发展方向

为什么选择Practical Modern JavaScript&#xff1a;探索ES6未来发展方向 【免费下载链接】practical-modern-javascript &#x1f3ca; Dive into ES6 and the future of JavaScript 项目地址: https://gitcode.com/gh_mirrors/pr/practical-modern-javascript Practic…...