当前位置: 首页 > 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;所以我开…...

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…...

R语言AI模型部署方案:精准离线运行详解

R语言AI模型部署方案:精准离线运行详解 一、项目概述 本文将构建一个完整的R语言AI部署解决方案,实现鸢尾花分类模型的训练、保存、离线部署和预测功能。核心特点: 100%离线运行能力自包含环境依赖生产级错误处理跨平台兼容性模型版本管理# 文件结构说明 Iris_AI_Deployme…...

UE5 学习系列(三)创建和移动物体

这篇博客是该系列的第三篇&#xff0c;是在之前两篇博客的基础上展开&#xff0c;主要介绍如何在操作界面中创建和拖动物体&#xff0c;这篇博客跟随的视频链接如下&#xff1a; B 站视频&#xff1a;s03-创建和移动物体 如果你不打算开之前的博客并且对UE5 比较熟的话按照以…...

家政维修平台实战20:权限设计

目录 1 获取工人信息2 搭建工人入口3 权限判断总结 目前我们已经搭建好了基础的用户体系&#xff0c;主要是分成几个表&#xff0c;用户表我们是记录用户的基础信息&#xff0c;包括手机、昵称、头像。而工人和员工各有各的表。那么就有一个问题&#xff0c;不同的角色&#xf…...

srs linux

下载编译运行 git clone https:///ossrs/srs.git ./configure --h265on make 编译完成后即可启动SRS # 启动 ./objs/srs -c conf/srs.conf # 查看日志 tail -n 30 -f ./objs/srs.log 开放端口 默认RTMP接收推流端口是1935&#xff0c;SRS管理页面端口是8080&#xff0c;可…...

从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(九)

设备树移植 和uboot设备树修改的内容同步到kernel将设备树stm32mp157d-stm32mp157daa1-mx.dts复制到内核源码目录下 源码修改及编译 修改arch/arm/boot/dts/st/Makefile&#xff0c;新增设备树编译 stm32mp157f-ev1-m4-examples.dtb \stm32mp157d-stm32mp157daa1-mx.dtb修改…...

接口自动化测试:HttpRunner基础

相关文档 HttpRunner V3.x中文文档 HttpRunner 用户指南 使用HttpRunner 3.x实现接口自动化测试 HttpRunner介绍 HttpRunner 是一个开源的 API 测试工具&#xff0c;支持 HTTP(S)/HTTP2/WebSocket/RPC 等网络协议&#xff0c;涵盖接口测试、性能测试、数字体验监测等测试类型…...

解析奥地利 XARION激光超声检测系统:无膜光学麦克风 + 无耦合剂的技术协同优势及多元应用

在工业制造领域&#xff0c;无损检测&#xff08;NDT)的精度与效率直接影响产品质量与生产安全。奥地利 XARION开发的激光超声精密检测系统&#xff0c;以非接触式光学麦克风技术为核心&#xff0c;打破传统检测瓶颈&#xff0c;为半导体、航空航天、汽车制造等行业提供了高灵敏…...

Python 训练营打卡 Day 47

注意力热力图可视化 在day 46代码的基础上&#xff0c;对比不同卷积层热力图可视化的结果 import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms from torch.utils.data import DataLoader import matplotlib.pypl…...

通过MicroSip配置自己的freeswitch服务器进行调试记录

之前用docker安装的freeswitch的&#xff0c;启动是正常的&#xff0c; 但用下面的Microsip连接不上 主要原因有可能一下几个 1、通过下面命令可以看 [rootlocalhost default]# docker exec -it freeswitch fs_cli -x "sofia status profile internal"Name …...