go test测试

go test基本介绍

go test命令是一个按照一定的约定和组织来测试代码的程序。在包目录内,所有以_test.go为后缀名的源文件在执行go build时不会被构建成包的一部分,它们是go test测试的一部分。

*_test.go文件中,有三种类型的函数

  • 测试函数
    一个测试函数是以Test为函数名前缀的函数,用于测试程序的一些逻辑行为是否正确;go test命令会调用这些测试函数并报告测试结果是PASS或FAIL。
  • 基准测试(benchmark)函数
    基准测试函数是以Benchmark为函数名前缀的函数,它们用于衡量一些函数的性能;go test命令会多次运行基准测试函数以计算一个平均的执行时间。
  • 示例函数
    示例函数是以Example为函数名前缀的函数,提供一个由编译器保证正确性的示例文档。

go test命令会遍历所有的*_test.go文件中符合上述命名规则的函数,生成一个临时的main包用于调用相应的测试函数,接着构建并运行、报告测试结果,最后清理测试中生成的临时文件。

详细介绍

测试函数

每个测试函数必须导入testing包。测试函数有如下的签名:

func TestName(t *testing.T) {// ...
}

测试函数的名字必须以Test开头,可选的后缀名必须以大写字母开头

func TestSin(t *testing.T) { /* ... */ }
func TestCos(t *testing.T) { /* ... */ }
func TestLog(t *testing.T) { /* ... */ }

其中t参数用于报告测试失败和附加的日志信息。让我们定义一个实例包gopl.io/ch11/word1,其中只有一个函数IsPalindrome用于检查一个字符串是否从前向后和从后向前读都是一样的。(下面这个实现对于一个字符串是否是回文字符串前后重复测试了两次;我们稍后会再讨论这个问题。)

gopl.io/ch11/word1

// Package word provides utilities for word games.
package word// IsPalindrome reports whether s reads the same forward and backward.
// (Our first attempt.)
func IsPalindrome(s string) bool {for i := range s {if s[i] != s[len(s)-1-i] {return false}}return true
}

在相同的目录下,word_test.go测试文件中包含了TestPalindrome和TestNonPalindrome两个测试函数。每一个都是测试IsPalindrome是否给出正确的结果,并使用t.Error报告失败信息:

package wordimport "testing"func TestPalindrome(t *testing.T) {if !IsPalindrome("detartrated") {t.Error(`IsPalindrome("detartrated") = false`)}if !IsPalindrome("kayak") {t.Error(`IsPalindrome("kayak") = false`)}
}func TestNonPalindrome(t *testing.T) {if IsPalindrome("palindrome") {t.Error(`IsPalindrome("palindrome") = true`)}
}

go test命令如果没有参数指定包那么将默认采用当前目录对应的包(和go build命令一样)。我们可以用下面的命令构建和运行测试。

$ cd $GOPATH/src/gopl.io/ch11/word1
$ go test
ok   gopl.io/ch11/word1  0.008s

go test命令如果没有参数指定包那么将默认采用当前目录对应的包(和go build命令一样)。我们可以用下面的命令构建和运行测试。

$ cd $GOPATH/src/gopl.io/ch11/word1
$ go test
ok   gopl.io/ch11/word1  0.008s

不过IsPalindrome函数不能识别“été”。也不能识别“A man, a plan, a canal: Panama.”。执行特殊和小的BUG报告为我们提供了新的更自然的测试用例。

func TestFrenchPalindrome(t *testing.T) {if !IsPalindrome("été") {t.Error(`IsPalindrome("été") = false`)}
}func TestCanalPalindrome(t *testing.T) {input := "A man, a plan, a canal: Panama"if !IsPalindrome(input) {t.Errorf(`IsPalindrome(%q) = false`, input)}
}

为了避免两次输入较长的字符串,我们使用了提供了有类似Printf格式化功能的 Errorf函数来汇报错误结果。
当添加了这两个测试用例之后,go test返回了测试失败的信息。

$ go test
--- FAIL: TestFrenchPalindrome (0.00s)word_test.go:28: IsPalindrome("été") = false
--- FAIL: TestCanalPalindrome (0.00s)word_test.go:35: IsPalindrome("A man, a plan, a canal: Panama") = false
FAIL
FAIL    gopl.io/ch11/word1  0.014s

先编写测试用例并观察到测试用例触发了和用户报告的错误相同的描述是一个好的测试习惯。只有这样,我们才能定位我们要真正解决的问题。

如果测试集有很多运行缓慢的测试,我们可以通过只选择运行某些特定的测试来加快测试速度。

参数-v可用于打印每个测试函数的名字和运行时间:

$ go test -v
=== RUN TestPalindrome
--- PASS: TestPalindrome (0.00s)
=== RUN TestNonPalindrome
--- PASS: TestNonPalindrome (0.00s)
=== RUN TestFrenchPalindrome
--- FAIL: TestFrenchPalindrome (0.00s)word_test.go:28: IsPalindrome("été") = false
=== RUN TestCanalPalindrome
--- FAIL: TestCanalPalindrome (0.00s)word_test.go:35: IsPalindrome("A man, a plan, a canal: Panama") = false
FAIL
exit status 1
FAIL    gopl.io/ch11/word1  0.017s

参数-run对应一个正则表达式,只有测试函数名被它正确匹配的测试函数才会被go test测试命令运行:

$ go test -v -run="French|Canal"
=== RUN TestFrenchPalindrome
--- FAIL: TestFrenchPalindrome (0.00s)word_test.go:28: IsPalindrome("été") = false
=== RUN TestCanalPalindrome
--- FAIL: TestCanalPalindrome (0.00s)word_test.go:35: IsPalindrome("A man, a plan, a canal: Panama") = false
FAIL
exit status 1
FAIL    gopl.io/ch11/word1  0.014s

当然,一旦我们已经修复了失败的测试用例,在我们提交代码更新之前,我们应该以不带参数的go test命令运行全部的测试用例,以确保修复失败测试的同时没有引入新的问题。

我们现在的任务就是修复这些错误。简要分析后发现第一个BUG的原因是我们采用了 byte而不是rune序列,所以像“été”中的é等非ASCII字符不能正确处理。第二个BUG是因为没有忽略空格和字母的大小写导致的。

针对上述两个BUG,我们仔细重写了函数:

gopl.io/ch11/word2

// Package word provides utilities for word games.
package wordimport "unicode"// IsPalindrome reports whether s reads the same forward and backward.
// Letter case is ignored, as are non-letters.
func IsPalindrome(s string) bool {var letters []runefor _, r := range s {if unicode.IsLetter(r) {letters = append(letters, unicode.ToLower(r))}}for i := range letters {if letters[i] != letters[len(letters)-1-i] {return false}}return true
}

同时我们也将之前的所有测试数据合并到了一个测试中的表格中。

func TestIsPalindrome(t *testing.T) {var tests = []struct {input stringwant  bool}{{"", true},{"a", true},{"aa", true},{"ab", false},{"kayak", true},{"detartrated", true},{"A man, a plan, a canal: Panama", true},{"Evil I did dwell; lewd did I live.", true},{"Able was I ere I saw Elba", true},{"été", true},{"Et se resservir, ivresse reste.", true},{"palindrome", false}, // non-palindrome{"desserts", false},   // semi-palindrome}for _, test := range tests {if got := IsPalindrome(test.input); got != test.want {t.Errorf("IsPalindrome(%q) = %v", test.input, got)}}
}

现在我们的新测试都通过了:

$ go test gopl.io/ch11/word2
ok      gopl.io/ch11/word2      0.015s

这种表格驱动的测试在Go语言中很常见。我们可以很容易地向表格添加新的测试数据,并且后面的测试逻辑也没有冗余,这样我们可以有更多的精力去完善错误信息。

失败测试的输出并不包括调用t.Errorf时刻的堆栈调用信息。和其他编程语言或测试框架的assert断言不同,t.Errorf调用也没有引起panic异常或停止测试的执行。即使表格中前面的数据导致了测试的失败,表格后面的测试数据依然会运行测试,因此在一个测试中我们可能了解多个失败的信息。

如果我们真的需要停止测试,或许是因为初始化失败或可能是早先的错误导致了后续错误等原因,我们可以使用t.Fatal或t.Fatalf停止当前测试函数。它们必须在和测试函数同一个goroutine内调用。

测试失败的信息一般的形式是“f(x) = y, want z”,其中f(x)解释了失败的操作和对应的输入,y是实际的运行结果,z是期望的正确的结果。就像前面检查回文字符串的例子,实际的函数用于f(x)部分。显示x是表格驱动型测试中比较重要的部分,因为同一个断言可能对应不同的表格项执行多次。要避免无用和冗余的信息。在测试类似IsPalindrome返回布尔类型的函数时,可以忽略并没有额外信息的z部分。如果x、y或z是y的长度,输出一个相关部分的简明总结即可。测试的作者应该要努力帮助程序员诊断测试失败的原因。

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

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

相关文章

【数据结构】--- 堆的应用

​ 个人主页:星纭-CSDN博客 系列文章专栏 :数据结构 踏上取经路,比抵达灵山更重要!一起努力一起进步! 一.堆排序 在前一个文章的学习中,我们使用数组的物理结构构造出了逻辑结构上的堆。那么堆到底有什么用呢&…

GO channel 学习

引言 单纯地将函数并发执行是没有意义的。函数与函数间需要交换数据才能体现并发执行函数的意义。 虽然可以使用共享内存进行数据交换,但是共享内存在不同的goroutine中容易发生竞态问题。为了保证数据交换的正确性,必须使用互斥量对内存进行加锁&#…

PostgreSQL 创建表格

PostgreSQL 创建表格 PostgreSQL 是一个功能强大的开源对象关系型数据库系统,它使用和扩展了SQL语言,并结合了许多安全存储和扩展最复杂数据工作负载的功能。在PostgreSQL中,创建表格是数据库设计的基础步骤之一,它定义了数据的结…

google 应用内评价

前言: 在应用内拉起 google 评价弹窗,用户提交 Play 商店的评分和评价,无需退出应用或游戏。应用内评价在应用的整个过程中随时触发。用户可以使用 1 到 5 星系统对您的应用进行评分,还可以选择添加评论。评价提交后将发送到 Pla…

016.自定义指纹chromium-随机tls指纹(ja4指纹)

自定义指纹chromium-随机tls指纹(ja4指纹) 一、什么是JA4指纹 JA4指纹可以理解成:将加密算法顺序排序后的ja3指纹。之前写过一篇博客介绍ja3指纹:插眼传送由于之前打乱算法顺序,只会改变ja3指纹和akamai指纹,ja4指纹并不会变。所…

虚拟专用网络(VPN)技术的研究与应用

随着信息技术的飞速发展和网络应用的日益普及,网络安全和隐私保护成为了人们关注的焦点。虚拟专用网络(VPN)作为一种重要的网络安全技术,通过在公共网络上建立专用网络,实现了数据的安全传输和用户隐私的保护。本文详细…

ASP.NET Core----基础学习06----将所有数据在页面中显示 布局页面的使用

文章目录 1. 将数据以list的形式展示在页面中2. 布局页面的使用3. 自定义设置视图文件是否需要加载的JS 1. 将数据以list的形式展示在页面中 step1:在接口文件中添加新的方法GetAllStudents() step2:在mock的数据中添加方法GetAllStudents(&a…

关于mogdb vs kingbase的测评 说明

上周5同事转了一个帖子给我,说某公众号写了一篇MogDB vs KingBase的文章测评。该博主使用sysbench测了一些场景,其中大部分场景Mogdb相比KingBase而言表现都要差一些,只有一个场景比kingbase高很多。 老实说第一眼看到这个文章,我…

谷歌Gemini产品大揭秘:AI新纪元即将到来!

谷歌在Google I/O大会上预告了五款备受瞩目的Gemini产品,预计于7月15日和7月18日发布。这些产品将包括新版Imagen3、Gemini定制GPT、个性化回应功能、预设提示词以及录音与Google Photos集成等。 AI-321 | 专注全球AI工具推荐的网站 Ai工具集 | 专注ai人工智能 | 集…

代码随想录算法训练营第37天

卡码网 52. 携带研究材料 链接 #include <iostream> #include <vector> using namespace std;int knapsack(int w, vector<int>& weight, vector<int>& value) {vector<int> dp(w 1, 0);for(int i 0; i < weight.size(); i) {for…

JNI: 在Kotlin和C++之间通过JNI进行接口传递,两边参数定义映射

在Kotlin和C之间通过JNI进行接口传递时&#xff0c;需要注意两边参数定义的映射关系。JNI&#xff08;Java Native Interface&#xff09;为Java&#xff08;Kotlin也适用&#xff09;与本地语言&#xff08;如C/C&#xff09;之间的交互提供了桥梁。在Kotlin中定义的外部函数和…

C语言指针超详解——强化篇

C语言指针系列文章目录 入门篇 强化篇 文章目录 C语言指针系列文章目录1. assert 断言2. 指针的使用和传址调用2. 1 strlen的模拟实现2. 2 传值调用和传址调用 3. 数组名的理解4. 使用指针访问数组5. 一维数组传参的本质6. 冒泡排序7. 二级指针8. 指针数组9. 指针数组模拟实现…

C语言 ——— 将一句英语短句中的单词进行倒置

目录 题目要求 代码实现 题目要求 将一句英语短句中的单词进行倒置&#xff0c;标点符号不倒置 如&#xff1a; 输入&#xff1a;"I like chongqing very much," 输出&#xff1a;"much, very chongqing like I" 代码实现 #include<stdio.h> #i…

MyBatis where标签替换WHERE 1 = 1会提升性能吗

MyBatis <where>标签替换WHERE 1 1会提升性能吗 查看项目早期数据库查询语句时&#xff0c;发现很多地方写了WHERE 1 1&#xff0c;怀疑这里有性能损失&#xff0c;想替换成<where>标签。 验证 已知索引 CREATE INDEX BP_LOG_BP_DATE_IDX ON QXX.BP_LOG (BP_…

java实战项目-学生管理系统(附带全套源代码及其登录注册功能的实现)--《进阶篇》

一、前言 新增了登录注册的功能&#xff0c;代码量可能会有点大&#xff0c;所有代码加起来差不多560行。这个项目对于小白来说肯定是一大难关了。文章中的每张图都是作者亲手绘制的&#xff0c;简单明了&#xff0c;如果大家认同作者&#xff0c;希望可以支持一下作者。全套源…

Mysql-索引应用

目录 索引应用 MySQL有哪些索引? 普通索引和唯一索引有什么区别? 哪个更新性能更好? 、 聚簇索引的主键索引怎么设置? 追问:假如你不设置会怎么样? 我们一般选择什么样的字段来建立索引? 索引越多越好吗? 索引怎么优化? &#xff08;覆盖索引优化、防止索引失效、…

论文翻译 | LEAST-TO-MOST: 从最少到最多的提示使大型语言模型中的复杂推理成为可能

摘要 思维链提示&#xff08;Chain-of-thought prompting&#xff09;在多种自然语言推理任务上展现了卓越的性能。然而&#xff0c;在需要解决的问题比提示中展示的示例更难的任务上&#xff0c;它的表现往往不佳。为了克服从简单到困难的泛化挑战&#xff0c;我们提出了一种新…

华为认证的证书有哪些?

华为认证的证书体系丰富多样&#xff0c;涵盖了多个技术领域和不同的认证级别。以下是对华为认证证书的主要分类和特点的归纳&#xff1a; 一、认证等级 技术认证是华为认证体系中的核心部分&#xff0c;主要分为以下三个级别&#xff1a; HCIA&#xff08;华为认证初级&…

算法的时间复杂度和空间复杂度-概念

一、算法效率 算法在编成可执行程序后&#xff0c;运行时需要耗费时间资源和空间&#xff08;内存&#xff09;资源&#xff0c;因此衡量一个算法的好坏&#xff0c;一般是由时间和空间两个维度来衡量的&#xff0c;即时间复杂度和空间复杂度。 时间复杂度主要衡量算法运行的…

3.3、matlab彩色图和灰度图的二值化算法汇总

1、彩色图和灰度图的二值化算法汇总原理及流程 彩色图和灰度图的二值化算法的原理都是将图像中的像素值转化为二值(0或1),以便对图像进行简化或者特定的图像处理操作。下面分别介绍彩色图和灰度图的二值化算法的原理及流程: 1)彩色图的二值化算法原理及流程 (1)原理:…