单元测试时go语言开发中的重要工具,也是每个程序员应当掌握的重要技能,今天让我们一起来学习一下go语言中的单元测试。
什么是单元测试?
单元测试(Unit Testing)是一种软件测试方法,用于验证软件中的最小可测试部分是否按照预期工作。最小可测试部分一般是单个函数或方法,而单元测试的目的就是是隔离代码无关于目标检测函数的部分来验证目标函数在不同输入或者环境下是否能保持正确性,确保每个单元在独立于系统的其他部分的情况下能够正常运行。一般单元测试应当有独立性、自动化、快速反馈、易于维护、高覆盖率等特点。
Go中的单元测试
单元测试的结构
Go语言提供了一个强大的单元测试框架来验证代码的执行正确性。每个单元测试函数都应该以 Test
为前缀,并且应该使用断言来验证函数的预期行为。所有单元测试函数都应该包含在以 _test.go
为后缀的文件中,以便于运行单元测试。这些单元测试确保代码在随机输入下输出正确的值,覆盖了一系列功能,包括简单函数、HTTP 端点或数据查询。一个单元测试文件应当包括以下几个重要的特征:
- 创建一个以 *test.go 为后缀的新文件,并将其保存在被验证文件的同一包中;
- 导入 testing 包;
- 编写以 test* 为前缀的测试函数,并带有输入参数 t *testing.T。
- 在函数内部,你可以使用 testing.T 方法和断言,例如 Error, Fail 或 Errorf 来报告失败。
- 使用 go test 来执行所有的 _test.go 文件。
单元测试的工具
- 断言
断言就是用一些规定好的函数来验证函数的行为是否跟我们预期的一致,否则会报告错误。断言有许多不同的类型,例如Equal/NotEqual/True/False。 - 子测试:
子测试是一种在单个函数内组织不同参数的不同测试实例的有效方式。你可以使用 t.run 来定义子测试。t.Run(tc.name, func(t *testing.T){ ... })。你可以检查哪个实例成功或失败。你也可以使用 go test -run TestXX/TestA 来指定执行哪个子测试。 - Testmain函数
如果有人想在测试前设置一些全局参数或在测试后进行一些清理工作,可以使用 TestMain 函数来自定义和控制测试的进行方式,例如手动调用测试函数。TestMain 函数应该在测试文件中只定义一次,有一个输入 *testing.M,没有输出。TestMain 函数调用 m.Run() 来启动测试,并返回一个状态码,该状态码被传递给 os.Exit() 以关闭程序。m.Run() 将执行所有的测试函数。如果你在测试文件中定义了 TestMain 函数,你将调用 TestMain 而不是执行所有的测试函数,但你必须要显式调用 m.Run() 以确保测试成功执行。
// 测试运行开始前的准备工作
}
func teardown() {
// 测试运行结束后的收尾工作
}
func TestMain(m \*testing.M) {
setup()
code := m.Run()
teardown()
os.Exit(code)
}
单元测试的执行
一般情况下,go运行单元测试都会以指令go test
为主,该指令会运行当前目录下所有包的测试文件。但是如果对于测试有特殊的要求,可以通过以下几种方式。
- 若想运行特定的单元测试函数,
go test -run TestName
。Test Name必须是已存的函数名称,并且支持正则表达式,例如go test -run 'TestName$'
。 - 若想显示测试覆盖率,
go test -cover
。 - 若想生成测试覆盖率文件,
go test -coverprofile=coverage.out
。创建一个名为coverage.out
的文件来存储覆盖率信息。 - 若想运行带有详细输出的测试,
go test -v
,将会输出每一个测试函数的名称和结果。 - 若想运行特定的测试包,
go test ./...
,./...
表明将会执行当前目录及其所有子目录中的测试。 - 若想运行基准测试,
go test -bench .
,-bench
参数可以接受一个正则表达式来运行规定的基准测试函数。 - 若想可以指定测试环境下的环境变量,
go test -env 'XXX=XXXX'
。 - 若想并行运行测试,
go test -parallel n
。 - 以上所有指令可以结合使用。
以上我们从定义、构成、工具和特定语法介绍了如何在go语言中编写和执行单元测试。一个好的测试文件可以帮助开发事半功倍,提高代码的可执行性和正确性,并帮助我们加深对与代码的理解,希望大家可以借助本文给出的东西在未来的代码编写中更好更高效的编写出代码和单元测试。