Go单元测试

Go 语言中,单元测试是通过标准库中的 testing 包来实现的,该包提供了一组功能,使得编写、运行和管理单元测试变得简单和高效。

一、规则

  • 测试文件的命名规则
    Go 中的测试文件命名规则是在被测试的源文件名后面加上 _test.go。例如,如果你有一个 calculator.go 文件,相应的测试文件应该是 calculator_test.go

  • 测试函数的命名规则
    测试函数必须以 Test 开头,后面可以跟任何非空字符串,例如 TestAddTestSubtract 等。

  • 使用 testing.T 进行断言和错误报告
    在测试函数中,使用 testing.T 类型的参数来管理测试状态和输出。你可以使用 t.Error*t.Fail* 等方法来指示测试失败,并输出相关的错误信息。

二、单元测试示例

2.1 单个测试用例

在calculator包中定义了一个calculator函数,具体实现如下:

package calculatorfunc Add(a, b int) int {return a + b
}

在当前目录下,我们创建一个calculator_test.go的测试文件,并定义一个测试函数如下:

package calculatorimport "testing"func TestAdd(t *testing.T) {result := Add(1, 2)expected := 3if result != expected {t.Errorf("Add(1,2) return %d, expected %d", result, expected)}
}

要运行这个单元测试,可以使用 go test 命令。在命令行中进入到包含 calculator.go 和 calculator_test.go 的目录,然后执行go test,这些结果如下

go test
PASS
ok      modu    0.226s

2.2 多个测试用例

在calculator_test.go中添加如下测试函数:

func TestAdd2(t *testing.T) {result := Add(3, 2)expected := 3if result != expected {t.Errorf("Add(1,2) return %d, expected %d", result, expected)}
}

为了能更好的在输出结果中看到每个测试用例的执行情况,我们可以为go test -v参数,让它输出完整的测试结果。

go test -v
=== RUN   TestAdd
--- PASS: TestAdd (0.00s)
=== RUN   TestAdd2calculator_test.go:17: Add(1,2) return 5, expected 3
--- FAIL: TestAdd2 (0.00s)
FAIL
exit status 1
FAIL    modu    0.216s

2.3 指定运行测试用例

go test -run 命令可以按照指定的模式运行测试。这个命令支持通过正则表达式来选择要运行的测试函数。

例如修正好TestAdd2用例之后,通过go tes -run=Add2只运行TestAdd2这个测试用例,结果是

go test -run=Add2 -v
=== RUN   TestAdd2
--- PASS: TestAdd2 (0.00s)
PASS
ok      modu    0.198s

4. 跳过某些测试用例
新加测试函数

func TestAdd3(t *testing.T) {if testing.Short() {t.Skip("short模式下会跳过该测试用例")}result := Add(3, 2)expected := 5if result != expected {t.Errorf("Add(1,2) return %d, expected %d", result, expected)}
}

当执行go test -short时,就会跳过testing.Short()标记的测试用例,结果是

go test -short -v
=== RUN   TestAdd
--- PASS: TestAdd (0.00s)
=== RUN   TestAdd2
--- PASS: TestAdd2 (0.00s)
=== RUN   TestAdd3calculator_test.go:23: short模式下会跳过该测试用例
--- SKIP: TestAdd3 (0.00s)
PASS
ok      modu    0.635s

三、测试组和子测试

3.1 测试组和子测试

通过测试组和子测试,可以更友好来添加更多的测试用例,以及查看结果

func TestAdd(t *testing.T) {tests := []struct {name     stringx, y     intexpected int}{{"Add1", 1, 2, 3},{"Add2", 3, 3, 6},{"Add3", 4, 5, 8},}for _, tc := range tests {t.Run(tc.name, func(t *testing.T) {result := Add(tc.x, tc.y)if result != tc.expected {t.Errorf("Add(%d, %d) returned %d, expected %d", tc.x, tc.y, result, tc.expected)}})}
}

运行go test -v,结果是

go test -v
=== RUN   TestAdd
=== RUN   TestAdd/Add2
=== RUN   TestAdd/Add3calculator_test.go:51: Add(4, 5) returned 9, expected 8
--- FAIL: TestAdd (0.00s)--- PASS: TestAdd/Add1 (0.00s)--- PASS: TestAdd/Add2 (0.00s)--- FAIL: TestAdd/Add3 (0.00s)
FAIL
exit status 1
FAIL    modu    0.190s

3.2 并行测试

Go语言天生支持并发,所以通过添加t.Parallel()来实现驱动测试并行化。

func TestAdd(t *testing.T) {t.Parallel()  // 将 TLog 标记为能够与其他测试并行运行// 这里使用匿名结构体定义了若干个测试用例// 并且为每个测试用例设置了一个名称tests := []struct {name     stringx, y     intexpected int}{{"Add1", 1, 2, 3},{"Add2", 3, 3, 6},{"Add3", 4, 5, 8},}for _, tc := range tests {tc := tc  // 注意这里重新声明tt变量(避免多个goroutine中使用了相同的变量)t.Run(tc.name, func(t *testing.T) {t.Parallel()  // 将每个测试用例标记为能够彼此并行运行result := Add(tc.x, tc.y)if result != tc.expected {t.Errorf("Add(%d, %d) returned %d, expected %d", tc.x, tc.y, result, tc.expected)}})}
}

3.3 测试覆盖率

使用go test -cover来查看测试覆盖率

go test -cover
PASSmodu    coverage: 100.0% of statements
ok      modu    1.149s

四、Go单元测试工具包 – testify

在进行Go语言单元测试时,由于官方并未内置断言功能,我们通常需要使用大量的if...else...语句来校验测试结果。然而,通过使用第三方库如testify/assert,我们可以轻松地调用多种常用的断言函数,这些函数不仅能够简化测试代码,还能生成清晰易懂的错误描述信息,帮助我们快速定位问题。

在上面例子当中,我们使用if...else...语句来校验测试结果

	for _, tc := range tests {t.Run(tc.name, func(t *testing.T) {result := Add(tc.x, tc.y)if result != tc.expected {t.Errorf("Add(%d, %d) returned %d, expected %d", tc.x, tc.y, result, tc.expected)}})}

现在可使用testify/assert之将上述判断过程简化如下:

	for _, tc := range tests {t.Run(tc.name, func(t *testing.T) {result := Add(tc.x, tc.y)assert.Equal(t, result, tc.expected)})}

testify/require拥有testify/assert所有断言函数,它们的唯一区别就是testify/require遇到失败的用例会立即终止本次测试。

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

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

相关文章

matplotlib下载安装

matplotlib下载安装过程同之前写的pygame很类似。 Pygame下载安装 python官网 1.搜索matplotlib 直接点进去 查看历史版本,因为新版本可能出现与python不匹配问题。 我选择3.6.3版本,因为我安装的python是3.8,可以匹配版本。同时window操…

Linux文件描述符与FILE指针互相转换

目录 1、文件描述符转换为 FILE 指针 2、FILE 指针转换为文件描述符 在Linux中,文件描述符(file descriptor, fd)和FILE指针(也称为文件流指针,FILE pointer)是两种常见的文件操作接口。文件描述符是一个…

Cesium与Three相机同步(3)

Cesium与Three融合的案例demo <!DOCTYPE html> <html lang"en" class"dark"><head><meta charset"UTF-8"><link rel"icon" href"/favicon.ico"><meta name"viewport" content&q…

C++ 类和对象 构造函数

一 类的6个默认成员函数&#xff1a; 如果一个类中什么成员都没有&#xff0c;简称为空类。 例&#xff1a; #include <iostream> class Empty {// 空类&#xff0c;什么成员都没有 }; 空类中真的什么都没有吗&#xff1f;并不是&#xff0c;任何类在什么都不写时&a…

洛谷 P1035 [NOIP2002 普及组] 级数求和

本文由Jzwalliser原创&#xff0c;发布在CSDN平台上&#xff0c;遵循CC 4.0 BY-SA协议。 因此&#xff0c;若需转载/引用本文&#xff0c;请注明作者并附原文链接&#xff0c;且禁止删除/修改本段文字。 违者必究&#xff0c;谢谢配合。 个人主页&#xff1a;blog.csdn.net/jzw…

qt 读取配置文件

在Qt中读取配置文件&#xff0c;主要有以下几种方法&#xff1a; 使用QFile和QTextStream类&#xff1a; 这种方法适用于读取任意文本文件&#xff0c;包括配置文件。使用QFile的open()方法打开配置文件。使用QTextStream的readLine()方法逐行读取配置数据。使用QXmlStreamRea…

谷粒商城学习-笔记大全

1&#xff0c;谷粒商城-01-项目介绍 2&#xff0c;谷粒商城笔记-02-项目整体效果展示 3&#xff0c;谷粒商城笔记-03-分布式基础概念 4&#xff0c;谷粒商城笔记-04-项目微服务架构图简介 5&#xff0c;谷粒商城学习笔记-05-项目微服务划分图 6&#xff0c;谷粒商城学习-06-使用…

【LinuxC语言】手撕Http协议之accept_request函数实现(一)

文章目录 前言accept_request函数作用accept_request实现解析方法根据不同方法进行不同操作http服务器响应格式unimplemented函数实现总结前言 在计算机网络中,HTTP协议是一种常见的应用层协议,它定义了客户端和服务器之间如何进行数据交换。在这篇文章中,我们将深入探讨Li…

C++模块化之内部类

目录 1.引言 2.内部类的访问控制 3.优缺点分析 4.实际运用 4.1.实现复杂数据结构 4.2.封装细节实现 4.3.事件处理和回调 4.4.模板元编程辅助类 4.5. 访问控制和封装 4.6. 代码组织和模块化 5.总结 1.引言 在C中&#xff0c;内部类&#xff08;Nested Class&#xff…

力扣爆刷第159天之TOP100五连刷61-65(翻转单词、对称二叉树、遍历求和)

力扣爆刷第159天之TOP100五连刷61-65&#xff08;翻转单词、对称二叉树、遍历求和&#xff09; 文章目录 力扣爆刷第159天之TOP100五连刷61-65&#xff08;翻转单词、对称二叉树、遍历求和&#xff09;一、151. 反转字符串中的单词二、129. 求根节点到叶节点数字之和三、104. 二…

简单解读伦敦银CFD(XAG)走势图

从本质上说&#xff0c;伦敦银是一种差价合约&#xff08;CFD&#xff09;交易&#xff0c;在同平台所提供的MT4中&#xff0c;它的代码也许并不一样&#xff0c;有的平台会显示为XAG&#xff0c;有的平台会显示为LLS或Silver&#xff0c;但它们指的其实是同一个品种&#xff0…

Python学习笔记29:进阶篇(十八)常见标准库使用之质量控制中的数据清洗

前言 本文是根据python官方教程中标准库模块的介绍&#xff0c;自己查询资料并整理&#xff0c;编写代码示例做出的学习笔记。 根据模块知识&#xff0c;一次讲解单个或者多个模块的内容。 教程链接&#xff1a;https://docs.python.org/zh-cn/3/tutorial/index.html 质量控制…

基于单片机的防酒驾控制系统设计

摘 要&#xff1a; 酒后驾车的危害十分巨大&#xff0c;因此&#xff0c;笔者介绍了一种基于单片机的防酒驾控制系统。系统由酒精传感器 MQ-3测量汽车驾驶员体内的酒精含量浓度&#xff0c;通过 A/D 转换器转换成数字信号传给单片机&#xff0c;经过单片机处理后显示酒精浓度&a…

c++11新特性-6-using

文章目录 using1.定义别名 using 1.定义别名 1.1 定义类型别名 using t int; 1.2 定义函数指针 int test(double,string){}//返回值类型 int &#xff0c;参数类型&#xff1a;double string using func int(*) (double,string);int main() {func f test;f(10.5,“hello…

算法训练营day69

查并集&#xff1a;107. 寻找存在的路径 (kamacoder.com) #include<iostream> #include<vector>using namespace std;vector<int> father(101, 0);void init() {for(int i 1;i < 101;i) {father[i] i;} }int find(int v) {if(v father[v]) return v;e…

老年生活照护实训室:为养老服务业输送专业人才

本文探讨了老年生活照护实训室在养老服务业专业人才培养中的关键作用。通过详细阐述实训室的功能、教学实践、对学生能力的培养以及面临的挑战和解决方案&#xff0c;强调了其在提升人才素质、满足行业需求方面的重要性&#xff0c;旨在为养老服务业的可持续发展提供有力的人才…

electron教程(二)控制应用程序的事件生命周期

1.will-finish-launching 当应用程序完成基础的启动的时候被触发&#xff0c;在 Windows 和 Linux 中, will-finish-launching 事件与 ready 事件是相同的; 在 macOS 中&#xff0c;这个事件相当于 NSApplication 中的 applicationWillFinishLaunching 提示。 app.on(will-fi…

Butterfly主题文章标题改成转动小风车

效果 标题级别不同小风车颜色不同&#xff0c;鼠标移入会有转动变慢及变色效果。 新建css 建议在/source下创建诸如img/css/js等文件夹&#xff0c;存放文章或网站用的素材&#xff0c;分门别类后续也方便维护。 Hexo打包的时候&#xff0c;会自动把/source下的文件&#…

深度神经网络语言识别

「AI秘籍」系列课程&#xff1a; 人工智能应用数学基础人工智能Python基础人工智能基础核心知识人工智能BI核心知识人工智能CV核心知识 使用 DNN 和字符 n-gram 对一段文本的语言进行分类&#xff08;附 Python 代码&#xff09; 资料来源&#xff0c;flaticon&#xff1a;htt…