高质量测试的12个步骤

news/2024/4/29 22:33:13/文章来源:https://blog.csdn.net/m0_67695717/article/details/127795070

简介

假设您正在实现某个功能,经过一番艰苦卓绝的编码后,终于可以提交、合并代码了。流水线开始运行,几分钟后失败了。部分单元测试用例失败了……这会让您很痛苦,因为修改的是别人遗留下来的程序,所以您并不清楚单元测试类的细节。搞清楚单元测试为什么失败以及理清楚他们之间的依赖关系可能是很有挑战的,会使原本1个小时的工作量变为一整天。

本文帮您提高测试类的质量,使之更易用。我通过12个步骤来度量测试类需要的改进。这个想法来源于“Joel测试:高质量代码的12个步骤”。这是一个评估软件团队质量的的方法。我非常认可这个想法,于是将它应用到测试中。就像Joel的测试一样,您不需要计算如同测试覆盖率以及其他不容易对齐的指标。只有12个问题,您都可以使用是或否来回答。每回答一个“是”,该测试类记1分。测试类的满分是12分,说明它很完美。同时,低于12分的就可以通过该问题进行有效的改善。

这些问题并没有涵盖所有涉及测试类易用性的因素。有些问题并不适合衡量测试类,因为您不能模拟所有东西。有可能有的非常完美的测试类,对这些问题的回答都是“不”。但是,如果能够对大多数问题回答为“是”的测试类,那么它的易用性就有极大的概率非常高。

1 测试是否独立

您应该能够以随机顺序运行测试,而不是让它们相互依赖。这使您的测试可维护性更高,因为您不必害怕影响其他测试。

2 测试是否可靠

您应该能够信赖您的测试。没有人喜欢在时而失败的构建或流水线上等待几分钟。能做的只是重新启动构建过程,祈祷这次不会失败。遗憾的是,修复这些测试的优先级很低,人们只会浪费时间重新启动并等待成功的构建。

3 测试是否高效

高效给出测试结果至关重要。您不会轻易分散精力,始终保持在工作流程中。当程序员在测试中等待超过10秒时,他们就会刷头条或者朋友圈。这会打断工作流程,而重新回到流程中需要一定的时间成本。更有可能的是,在花费太多时间的时候,人们会通过忽略或者注释来绕过测试。

4 Before和After是否与每个测试相关

在每次测试之前和之后做一些事情是减少重复代码的好方法。然而,当不是每个测试用例都需要这个特定的初始状态时,它就会成为一个问题。从那一刻起,您不仅在浪费 CPU 和时间,而且还使测试的维护成本剧增。Before 注解方法可能会为不需要它的测试用例创建不需要的状态。

实现 Before 和 After 的更好方法是使用参数化测试。您还可以使用子类将需要 Before 和 After 方法的测试用例与不需要该行为的测试用例分开。

在以下示例中,嵌套类将 Before 与父类分开。

public class StepsToBetterTests {Car car;@Testvoid testA(){car = new Car();Assertions.assertEquals(5, car.getSpeed());}@Nestedclass subTests{@BeforeEachvoid setUp() {car = mock(Car.class);when(car.getSpeed()).thenReturn(10);}@Testvoid subtestA(){Assertions.assertEquals(10, car.getSpeed());}}class Car{public int getSpeed(){return 5;}}}

5 测试是否单一

一个单元测试应该只覆盖一个测试用例。这使得测试更容易理解。否则,当单元测试失败时,您必须找出哪些用例失败了;当然,这些都没有很好的记录。

6 测试是否没有重复

维护的代码越少越好。测试用例也是如此;有时,您必须测试方法在不同输入和输出的表现。例如,当你测试一个计算器时,你会尝试不同的数字来查看计算是否正确。不要多次复制粘贴测试用例并且只更改参数,而是检查您的框架是否具有参数化测试用例之类的能力。

在以下示例中,使用参数化测试来测试add方法。

private static Stream<Arguments> valuesAndExpectedResultForAdd() {return Stream.of(Arguments.of(1, 1, 2),Arguments.of(2, 1, 3),Arguments.of(4, 2, 6));}@ParameterizedTest(name = "adding {0} and {1} expected result: {2}")@MethodSource({"valuesAndExpectedResultForAdd"})void add_shouldAddNumbersTogether(int firstInteger, int secondInteger, int expectedResult) {assertEquals(add(firstInteger, secondInteger), expectedResult);}

7 是否使用了每个模拟方法和对象

一些模拟框架默认不是很严格。因此,可以在不使用或设置任何期望的情况下创建模拟。通过对模拟的期望行为更加精确和明确,您可以提高测试的质量和可维护性。

不太严格的测试可能更难调试。您最终可能会遇到使用错误配置的模拟并导致测试失败的情况。

8 测试是否有逻辑顺序

如同生产代码有顺序一样,单元测试中的代码也是如此。我喜欢以 Given-When-Then 风格编写单元测试。这种风格清楚地描述了测试用例需要什么、执行什么操作以及何时执行。单元测试将由以下三个部分组成:

  • 输入:创建测试用例所需的对象和模拟;
  • 条件:您要测试的操作;
  • 预期:您要执行的结果和断言。

并不要求每个人都使用这种风格,但是你的测试类或项目中的每个单元测试都应该使用一种连贯的风格。这样,每个人都清楚如何阅读和编写测试用例。

9 是否了解测试框架

当您了解测试框架和依赖项时,编写测试会变得更容易。您不必知道细节;只需知道框架的能力以及它提供的测试方法即可。因此,当您需要这些方法时,您可以查找它们。这可以防止您重新造轮子从而节省您的时间。

使用框架提供的最佳实践和方法,使您的测试更具可读性、可维护性和更易于编写。因此,您可以专注于如何用您的测试用例覆盖需求。

在我作为开发人员的六年中,这对我帮助最大。

10 测试需求还是实现

理想的测试只需要一些输入并验证输出是否正确。可悲的是,现实世界中的测试有点混乱,需要一些初始状态、模拟等。

当您编写测试以查看您是否正确实现了需求时,您可以使测试更能抵抗生产代码中的更改。目标是编写测试来验证答案是否正确,而无需与生产代码紧密耦合。

11 测试是否明确

在编写测试时,您应该有非常明确的预期结果。测试终端时,不仅要检查HTTP报文体,还要检查状态码是否符合预期。

另一个例子是像Mockito这样的测试框架。无论输入参数如何,Mockito都允许您对方法进行调用。这可能会导致不明确的结果。因此,不要使用 any() 并允许任何值,而是明确并说明您希望传递的值。这将使您的测试更加明确,并使失败更加明显。

@Testvoid LessExplicit(){// Givencar = mock(Car.class);// Here, we don't specify what number we expect but always return a correct response.when(car.shiftGear(anyInt())).thenReturn(10);// Whenint gear = car.shiftGear(10);// ThenAssertions.assertEquals(10, gear);}@Testvoid MoreExplicit(){// Givencar = mock(Car.class);// Here, we make explicit what input and output we expect from the mock.when(car.shiftGear(10)).thenReturn(10);// Whenint gear = car.shiftGear(10);// ThenAssertions.assertEquals(10, gear);}

12 测试是否简单

写一个好的测试已经够难了,所以应该使其可读性更高,因为它会被大量阅读。理想情况下,测试应该是显而易见的并明显展示测试目的。测试代码应该纯净并针对直观性和明确性进行优化。为了使您的测试易于理解,您可以尝试遵循本文中的其他建议或在查找网上资源。

两条最重要的建议是:了解您的测试框架的能力;对您的测试和测试代码进行逻辑排序。


资源分享

下方这份完整的软件测试视频学习教程已经上传CSDN官方认证的二维码,朋友们如果需要可以自行免费领取 【保证100%免费】

在这里插入图片描述

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_223839.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

docker环境连接tdengine服务

1.开发app项目 <!--引入TDEngine--> <dependency><groupId>com.taosdata.jdbc</groupId><artifactId>taos-jdbcdriver</artifactId><version>3.0.0</version> </dependency> <!-- 引入jdbc --> <dependency&g…

Vue(四)——使用脚手架(1)

安装和启动&#xff1a; 目录 分析脚手架结构 render函数 修改默认配置 ref属性 props配置项 mixin混入 插件 scoped样式 分析脚手架结构 脚手架文件结构 ├── node_modules ├── public│ ├── favicon.ico: 页签图标│ └── index.html: 主页面├── …

【Linux修炼手册:基本指令(上)】

目录 1 ls 指令 2 pwd命令 3 cd 指令 4 touch指令 5 mkdir指令&#xff08;重要&#xff09; 6 rmdir指令 && rm 指令&#xff08;重要&#xff09; 7 cp指令&#xff08;重要&#xff09; 8 mv指令&#xff08;重要&#xff09; 9 cat 总结&#xff1a; 1 ls…

C语言如何做到四舍五入保留小数

C语言中的格式化打印 : 例如&#xff1a; printf("%.2f",21.195); 输出是 21.20 四舍五入保留了定义宏变量 #define 即符号常量 也能够四舍五入保留 而变量和常变量 并不四舍五入&#xff1a; float a21.195 ;const float b21.195;printf("%.2f \n %.2f&quo…

Java本地搭建宝塔部署实战springboot工艺管理系统源码

大家好啊&#xff0c;我是测评君&#xff0c;欢迎来到web测评。 本期给大家带来一套java开发的工艺管理系统源码&#xff0c;该系统是前后端分离的架构&#xff0c;前端使用Vue2&#xff0c;后端使用SpringBoot2。 技术架构 技术框架&#xff1a;SpringBoot2.0.0 Mybatis1.3.…

【linux】stat文件属性中三个时间的区别(Access time,Modify time,Change time)

在了解这三个时间之前&#xff0c;我们了解什么是stat。 stat 文件名/目录 表示查看这个文件或者目录的属性&#xff0c;当然属性中包括我们的三个时间属性。 例如&#xff1a; OK&#xff0c;了解完stat之后 ,我们开始进入主题&#xff1a;Access time,Modify time,Change t…

几款很好看的爱心表白代码(动态)

分享几款好看的爱心表白代码❤️爱心代码❤️&#xff08;C语言&#xff09;❤️流动爱心❤️&#xff08;htmlcssjs&#xff09;❤️线条爱心❤️&#xff08;htmlcssjs&#xff09;❤️biu表白爱心❤️&#xff08;htmlcssjs&#xff09;❤️matlab爱心函数❤️&#xff08;需…

LSTM--火灾温度预测

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f366; 参考文章地址&#xff1a; 365天深度学习训练营-第R2周&#xff1a;LSTM-火灾温度预测&#x1f356; 作者&#xff1a;K同学啊一句话介绍LSTM&#xff0c;它是RNN的进阶版&#xff0c;如果…

静态路由———初学

文章目录实验需求:关键命令&#xff1a;静态路由默认路由实验配置接下来是配置pc的IP地址静态路由的配置保存实验需求: PC1 在 LAN1 中&#xff0c;PC2 在 LAN2 中&#xff0c;使用静态路由实现 pc1 和 pc2 之间的互相通信 本实验使用Cisco Packet Tracer 模拟器搭建 所有的路…

公考求的是稳定,搞IT求的是高薪,鱼和熊掌能否兼得?

程序员和公务员&#xff0c;大概是最让大家耳熟能详的两种职业。 这也是中国现代年轻人最具有代表性的两种职业。 程序员是从事程序开发、程序维护的专业人员。一般将程序员分为程序设计人员和程序编码人员&#xff0c;但两者的界限并不非常清楚&#xff0c;特别是在中国。软…

Verilog功能模块——Uart收发

摘要本文分享了一种通用的Uart收发模块&#xff0c;可实现Uart协议所支持的任意波特率&#xff0c;任意位宽数据&#xff08;5~8&#xff09;&#xff0c;任意校验位&#xff08;无校验、奇校验、偶校验、1校验、0校验&#xff09;&#xff0c;任意停止位&#xff08;1、1.5、2…

前端反爬思考,好友从百度搜到了我的文章,链接却是别人的

今天感叹可以改完八阿哥早点下班&#xff0c;在吃饭的时候&#xff0c;就想着自己也写了一段时间了&#xff0c;看看百度这个强大的引擎能不能搜到我的博客文章。 1、发现文章被爬走了 吃饭的时候用手机搜的&#xff0c;感觉还挺开心&#xff0c;我还给朋友炫耀&#xff0c;你看…

Import Error: from torchtext.data import to_map_style_dataset解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。喜欢通过博客创作的方式对所学的知识进行总结与归纳,不仅形成深入且独到的理…

电子统计台账:快速设置产品的排除与保留

目录 1 基础操作 2 设置垂直过滤模板 2.1 排除法 2.2 保留法 3 完成其他设置 4 小提示&#xff1a;项目导入导出 实践中&#xff0c;企业数据文件中可能有很多产品&#xff0c;中间混杂诸如“累计”、“合计”、“报表人”、“企业负责人”等信息。我们需要用简单的操作完…

洛谷千题详解 | P1018 [NOIP2000 提高组] 乘积最大【C++、Python、Java、pascal语言】

博主主页&#xff1a;Yu仙笙 专栏地址&#xff1a;洛谷千题详解 目录 题目描述 输入格式 输出格式 输入输出样例 解析&#xff1a; C源码&#xff1a; Python源码&#xff1a; Pascal源码&#xff1a; Java源码&#xff1a; -------------------------------------------------…

苯丙氨酸甲酯双三氟甲基磺酰亚胺[PheC1][Tf2N]氨基酸酯离子液体

苯丙氨酸甲酯双三氟甲基磺酰亚胺[PheC1][Tf2N]氨基酸酯离子液体 纯度&#xff1a;95% 外观与形状:液体/固体, 储存:存放于惰性气体之中 应避免湿气 (吸湿) 包装规格(Packing):50g、100g、500g 保存方法&#xff1a;密闭&#xff0c;阴凉&#xff0c;通风干燥处 氨基酸酯…

返回Series或DataFrame中指定列中指定数量的最小值nsmallest()函数

【小白从小学Python、C、Java】 【计算机等级考试500强双证书】 【Python-数据分析】 返回Series或DataFrame中 指定列中指定数量的最小值 nsmallest()函数 [太阳]选择题 下列说法错误的是? import pandas as pd mySeries pd.Series([31, 21, 11]) print("【显示】mySer…

Numpy手撸softmax regression

算法介绍 Softmax 回归&#xff08;或多项逻辑回归&#xff09;是将逻辑回归推广到我们想要处理多个类的情况。 在逻辑回归中&#xff0c;我们假设标签是二元的&#xff1a;y(i)∈{0,1}y^{(i)} \in \{0,1\}y(i)∈{0,1},我们使用这样的分类器来区分两种手写数字。 Softmax 回归…

C#项目实战|人脸识别考勤

此文主要通过WinForm来制作的一个人脸识别考勤打卡程序&#xff0c;有兴趣的小伙伴可以接入到打卡机上。 一、实现流程1.1、创建项目1.2、设计页面1.3、创建应用1.4、获取Token及参数解析1.5、与人脸数据比对并展示一、实现流程 1.1、创建项目 打开Visual Studio&#xff0c;右…

值得入手的键盘——Keychron K8 Pro

目录 一、前言 二、介绍 三、上手体验 四、总结 一、前言 在如今&#xff0c;外设产品市场相当火爆的时代&#xff0c;拥有诸多知名的品 牌&#xff0c;而一个新品牌要在竞争非常激烈的情况下站稳脚跟&#xff0c;实属不易。诞生于2017年的 Keychron 以其品质作为高端战略…