优测云测试平台 | 有效的单元测试(下)
接着上一篇内容,我们继续~
四、测试的目标之三:快速反馈
测试的快速反馈有两个方面的含义:
-
1.测试运行要快速出结果。
-
2.当测试失败时,要能快速定位失败原因。
测试运行效率决定了开发的工作周期运转的快慢。在理想的 TDD 模型中,开发人员一遍又一遍地重复着“测试 -> 实现 -> 测试“ 这样的周期循环,直到所有用例通过。持续集成和持续交付的过程也是如此。不管是单元测试还是大型测试,运行效率都是应该追求的目标。
同样在的道理,当测试出现用例失败时,如果我们要花很长的时间来定位到原因,也会拖慢我们从“测试”到“实现”的速度。要提高快速定位的能力,一方面要提高被测代码的可观测性,另一方面要给用例合理命名,还有在断言时加入有价值,易读易懂的 message. 在去年的一次分享中,已经提到过如何建设被测系统的可观测性并且做了一些支撑工具。在用例命名和断言信息方面,越是大型测试要求越高,因为其所覆盖的代码范围广,失败节点多,而在单测中则相对要求低一些,因为其被测代码覆盖范围小,相对容易定位。
但是!在单元测试时依然要认真给用例命名,充分添加断言信息。这一建议单独另起一段,考虑的是当我们写单测时的心智问题。不少开发在写单测时多心智是:“单测是写给我自己看的,这个用例测试的是我负责的代码,出了问题我很快就知道定位”,但是从团队和业务的角度出发,测试都是写给整个开发团队看的,这与代码的 readability 是一样的。code for team, test for team! 测试用例怎样命名,断言信息写些啥,有很多博客和问答可以提供参考.这里提供一个建议:在命名和添加断言信息时,想象着它们在报告中是如何显示的。以下用一个实际的例子来对比一下断言信息好坏的明显区别。
用例 v1
func TestQueryRecentExecs(t *testing.T) {t.Run("count 100 is too large", func(t *testing.T) {proxy := clientProxy()ctx, cancelFunc := context.WithTimeout(context.Background(), time.Second*5)defer cancelFunc()req := &caselog.QueryCaseRecentExecsRequest{CaseId: 5,Count: 100,}_, err := proxy.QueryCaseRecentExecs(ctx, req)require.Error(t, err)assert.Equal(t, errs.ErrorTypeBusiness, trpcErrType(err))})
}
该用例中,被测接口要求入参中
Count
不能大于等于 100,我们向被测服务发起异常参数的请求,期望其返回业务类型的错误(不能返回框架类型的错误,框架类型的错误是诸如服务寻址失败,超时之类的,跟业务无关的错误,具体参考 trpc 错误手册)。某次运行用例失败后得到的 log 如下:
test log v1
Failed
=== RUN TestQueryRecentExecs/count_100_is_too_largecaselog_test.go:56: Error Trace: caselog_test.go:56Error: Not equal: expected: 2actual : 1Test: TestQueryRecentExecs/count_100_is_too_large--- FAIL: TestQueryRecentExecs/count_100_is_too_large (2.00s)
从这个错误信息中,我们从用例名中知道目的是验证
Count
值为 100 过大而产生错误,但是在错误信息中我们读到的是“因为我们期望 2 而实际值为 1,用例失败”。这里 2 和 1 分别是什么?没有信息。
下面进行一版改进:
用例 v2
func TestQueryRecentExecs(t *testing.T) {t.Run("large count 100 cause biz error", func(t *testing.T) {proxy := clientProxy()ctx, cancelFunc := context.WithTimeout(context.Background(), time.Second*5)defer cancelFunc()req := &caselog.QueryCaseRecentExecsRequest{CaseId: 5,Count: 100,}_, err := proxy.QueryCaseRecentExecs(ctx, req)require.Error(t, err)assert.Equal(t, "business", trpcErrTypeName(err), "unexpected trpc error type")})
}
test log v2
Failed
=== RUN TestQueryRecentExecs/large_count_100_cause_biz_errorcaselog_test.go:80: Error Trace: caselog_test.go:80Error: Not equal: expected: "business"actual : "framework"Diff:--- Expected+++ Actual@@ -1 +1 @@-business+frameworkTest: TestQueryRecentExecs/large_count_100_cause_biz_errorMessages: unexpected trpc error type--- FAIL: TestQueryRecentExecs/large_count_100_cause_biz_error (0.81s)
v2 中很明确,trpc error type 与预期不符,预期是 business 而实际值为 framework. 这是一个接口测试,出现 Framework error 通常是被测服务没有正确部署或者测试流水线所在网络环境与被测服务不通。(用例中使用 testify 断言,其断言格式固定,可能不一定是最好的格式,略显啰嗦,但是它在其他方面比较方便,为了整个项目统一我们只能“因地制宜”。更简洁的断言信息是
t.Errorf("QueryCaseRecentExecs response error type mismatch got = %s, want = %s", trpcErrTypeName(err), "business")
即使该用例不是我写的,只要具备基本的 trpc 背景知识,看到报告后第一反应就是去确认被测服务是否健康,以及流水线网络环境是否正确,而在 v1 中,我可能还得打开 ide 查看一下用例代码,看用例代码还只能知道不是 business 错误,实际是什么错误并不知道,还得跳转到 trpc 的源代码才知道 1 是 framework 错误。(还有另一种错误是 “callee framework”)。孰快孰慢一目了然。
五、测试的第四个目标:用例集的可维护性
-
1.功能代码有可读性要求,测试代码也有,同样,功能代码有可维护性要求,测试代码也有可维护性要求。可维护性最佳实践与功能代码是相通的,仅举几例:
DRY, 以提取函数/提取常量来替代复制粘贴。 -
2.以配置代替写死值,可以参考一些 go 的标准库里面单元测试的方法,可以在测试时指定 flag,在用例中 parseFlags 来读取配置。
-
3.不要滥用设计模式,测试代码复杂度不宜过高,否则我们是否还有给测试代码写测试代码?
参考阅读
《Unit Testing: Principles, Practices, and Patterns》
脚注
[1]覆盖率并不一定是越高越好,对于没有测试价值的,低风险的代码,强行覆盖会消耗过多的时间和精力。怎样定一个覆盖率红线是另一个话题,长话短说就是代码库的 owner 自行决定才是最科学的。
[2]那些单元测试已经充分测试过的逻辑,无需在接口测试和端到端测试中重复。
优测测试平台简介:
是一个为企业与开发者提供专业的测试工具和服务的平台,沉淀十年产品测试经验,提供终端测试、接口测试、性能测试、安全测试等多领域测试服务与产品,协助客户提高效率降低成本,保证产品质量。
相关文章:
优测云测试平台 | 有效的单元测试(下)
接着上一篇内容,我们继续~ 四、测试的目标之三:快速反馈 测试的快速反馈有两个方面的含义: 1.测试运行要快速出结果。 2.当测试失败时,要能快速定位失败原因。 测试运行效率决定了开发的工作周期运转的快慢。在理想的 TDD 模型中&#x…...
CUDA安装
在cmd中输入nvidia-smi。显示CUDA Version:12.3,所以只能下载小于等于12.3的版本。如下图: 进这个网址:https://developer.nvidia.com/cuda-toolkit-archive 选择一个版本下载。 选择完后之后这样选择: 最后点击下载即…...
【XTDrone Ubuntu18.04】XTDrone + Ubuntu18.04 + PX4 安装过程
重新配置所有的软件 卸载之前安装的ROS GAZEBO 记得把/home下的.ros和.gazebo也删除,删就删干净 参考链接:ROS的卸载与安装 血泪总结!亲测有效 卸载ROS方法 正式安装 安装依赖 sudo apt install ninja-build exiftool ninja-build protobuf…...
网站使用什么协议比较好
网站协议大多数使用HTTP和HTTPS HTTP协议,超文本传输协议(Hypertext Transfer Protocol,HTTP)是一个简单的请求-响应协议。 HTTP是应用层协议,同其他应用层协议一样,是为了实现某一类具体应用的协议&…...
18. 机器学习——集成学习
机器学习面试题汇总与解析——集成学习 本章讲解知识点 什么是集成学习AdaBoost梯度提升树(Gradient Boosting Decision Tree, GBDT)随机森林(Random Forest,简称RF)XGBoostLightGBM本专栏适合于Python已经入门的学生或人士,有一定的编程基础。 本专栏适合于算法工程师、机器…...
SimaPro生命周期评估建模与碳足迹分析流程
SimaPro以系统和透明的方式轻松建模和分析复杂的生命周期,通过确定供应链中每个环节的热点,从原材料的提取到制造,分销,使用和处置,衡量所有生命周期阶段的产品和服务对环境的影响。SimaPro是过去25年评估生命周期的最…...
我的项目分享(不喜勿喷)
我要分享的项目是大喇叭C2C电商平台系统,一个面向移动端的电子商务平台,为个体消费者和商家提供直接交易和沟通的便利,丰富了人们的生活。 主要功能模块: 该项目的主要功能包括: 1. 用户注册功能:使用正则…...
PyTorch:张量与矩阵
PyTorch 是一个基于 Python 的科学计算包,专门针对深度学习研究,提供了丰富的工具和库。在 PyTorch 中,张量(tensor)是深度学习的核心数据结构,它可以看作是可以进行自动微分的多维数组。张量不仅可以代表标…...
传统广电媒体为何选择上云?有何优势?
随着现在互联网和科技的发展,现在更多的行业都搭上了科技这辆快车快速的完成了转型,那么在传统的广电媒资行业他们目前有哪些痛点呢?传统广电媒体转型发展现状是什么?企业如何数字化转型?企业上云的优势有哪些…...
系列十、堆参数调优
一、堆内存调优参数 -Xms堆空间的最小值,默认为物理内存的1/64-Xmx堆空间的最大值,默认为物理内存的1/4-XX:PrintGCDetails输出详细的GC处理日志 二、获取堆内存的默认物理内存 /*** Author : 一叶浮萍归大海* Date: 2023/11/16 14:50* Description: 获…...
sqlite3简单使用
为什么要使用sqlite3? sqlite3轻量简介,无需单独的数据库服务,只需访问磁盘上的.db的文件。在某些情况下很有用。 下面是一些简单的使用代码: import sqlite3 from uuid import uuid1# 连接数据库文件,如果不存在会创建 with…...
实测文心一言4.0,真的比GPT-4毫不逊色吗?
10月17日,李彦宏在百度世界2023上表示。当天,李彦宏以《手把手教你做AI原生应用》为主题发表演讲,发布文心大模型4.0版本。 今天,咱们就开门见山啊。这一回要测一测,昨天才发布的文心一言大模型 4.0。 之所以要测它&…...
损失函数——KL散度(Kullback-Leibler Divergence,KL Divergence)
KL散度(Kullback-Leibler Divergence,简称KL散度)是一种度量两个概率分布之间差异的指标,也被称为相对熵(Relative Entropy)。KL散度被广泛应用于信息论、统计学、机器学习和数据科学等领域。 KL散度衡量的…...
基于springboot的医护人员排班系统 全套代码 全套文档
基于springboot的医护人员排班系统,springboot vue mysql (毕业论文10411字以上,共27页,程序代码,MySQL数据库) 代码下载链接:https://pan.baidu.com/s/177HdCGtTvqiHP4O7qWAgxA?pwd0jlf 提取码:0jlf 【运行环境】 IDEA, JDK1.8, Mysql, Node, Vue …...
【YOLOX简述】
YOLOX的简述 一、 原因1. 背景2. 概念 二、 算法介绍2.1 YOLOX算法结构图:2.2 算法独特点2.3 Focus网络结构2.4 FPN,PAN2.5 BaseConv2.6 SPP2.7 CSPDarknet2.8 YOlO Head 三、预测曲线3.1 曲线 一、 原因 1. 背景 工业的缺陷检测是计算机视觉中不可缺少…...
一文带你深入浅出Web的自动化测试工具Selenium【建议收藏】
文章目录 前言第01节 Selenium概述第02节 安装浏览器驱动(以Google为例)第03节 定位页面元素1. 打开指定页面2. id 定位3. name 定位4. class 定位5. tag 定位6. xpath 定位7. css 选择器8. link 定位9. 示例 有道翻译 第04节 浏览器控制1. 修改浏览器窗…...
Django模版层
解析: forloop内置对象:运行结果解析 counter0: 从0开始计数 counter : 从1开始计数 first: True,判断循环的开始 last : Tues,判断循环的结束模版变量的书写 我们可以在html中编写python代码。 演示: {{ 填写变量 }}{% 填写类的 %}{{ d.0 }} {{ d.1 }…...
同一个IP地址可有不同的写法?
每个人在上网的时候,都会被分配一个IP地址,这是互联网世界中的“身份证号码”。IP地址是以数字形式呈现的,例如192.168.1.1。然而,你是否知道,尽管一个IP地址的数字串唯一标识一个设备,但它可以有不同的写法…...
《Effective C++》条款13
以对象管理资源 有这样一段代码: class A { public:A* create(){...}}; class B :public A { public:A* ptr create();...delete ptr; }; 我们定义了ptr去接收create()函数的返回值,并且在最后进行了回收资源。看似是没问题的。但是实际上有很多隐患&am…...
【入门Flink】- 09Flink水位线Watermark
在窗口的处理过程中,基于数据的时间戳,自定义一个“逻辑时钟”。这个时钟的时间不会自动流逝;它的时间进展,就是靠着新到数据的时间戳来推动的。 什么是水位线 用来衡量事件时间进展的标记,就被称作“水位线”&#x…...
stm32G473的flash模式是单bank还是双bank?
今天突然有人stm32G473的flash模式是单bank还是双bank?由于时间太久,我真忘记了。搜搜发现,还真有人和我一样。见下面的链接:https://shequ.stmicroelectronics.cn/forum.php?modviewthread&tid644563 根据STM32G4系列参考手…...
P3 QT项目----记事本(3.8)
3.8 记事本项目总结 项目源码 1.main.cpp #include "widget.h" #include <QApplication> int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); } 2.widget.cpp #include "widget.h" #include &q…...
多模态大语言模型arxiv论文略读(108)
CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文标题:CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文作者:Sayna Ebrahimi, Sercan O. Arik, Tejas Nama, Tomas Pfister ➡️ 研究机构: Google Cloud AI Re…...
4. TypeScript 类型推断与类型组合
一、类型推断 (一) 什么是类型推断 TypeScript 的类型推断会根据变量、函数返回值、对象和数组的赋值和使用方式,自动确定它们的类型。 这一特性减少了显式类型注解的需要,在保持类型安全的同时简化了代码。通过分析上下文和初始值,TypeSc…...
WebRTC从入门到实践 - 零基础教程
WebRTC从入门到实践 - 零基础教程 目录 WebRTC简介 基础概念 工作原理 开发环境搭建 基础实践 三个实战案例 常见问题解答 1. WebRTC简介 1.1 什么是WebRTC? WebRTC(Web Real-Time Communication)是一个支持网页浏览器进行实时语音…...
协议转换利器,profinet转ethercat网关的两大派系,各有千秋
随着工业以太网的发展,其高效、便捷、协议开放、易于冗余等诸多优点,被越来越多的工业现场所采用。西门子SIMATIC S7-1200/1500系列PLC集成有Profinet接口,具有实时性、开放性,使用TCP/IP和IT标准,符合基于工业以太网的…...
高分辨率图像合成归一化流扩展
大家读完觉得有帮助记得关注和点赞!!! 1 摘要 我们提出了STARFlow,一种基于归一化流的可扩展生成模型,它在高分辨率图像合成方面取得了强大的性能。STARFlow的主要构建块是Transformer自回归流(TARFlow&am…...
大模型智能体核心技术:CoT与ReAct深度解析
**导读:**在当今AI技术快速发展的背景下,大模型的推理能力和可解释性成为业界关注的焦点。本文深入解析了两项核心技术:CoT(思维链)和ReAct(推理与行动),这两种方法正在重新定义大模…...
【汇编逆向系列】四、函数调用包含单个参数之Double类型-mmword,movsd,mulsd,addsd指令,总结汇编的数据类型
一、汇编代码 上一节开始,讲到了很多debug编译独有的汇编方式,为了更好的区分release的编译器优化和debug的区别,从本章节开始将会提供debug和release的汇编用作对比 Debugb编译 single_double_param:00000000000000A0: F2 0F 11 44 24 08…...
NoSQL——Redis配置与优化
目录 关系型&非关系型数据库 一、核心原理对比 二、核心特性对比 三、关键区别剖析 四、典型产品示例 总结 Redis Redis核心原理 核心特性 技术意义 配置文件解析 1. 基础配置 2. 持久化配置 3. 内存管理 4. 高可用配置 5. 性能调优 6.…...
