您的位置:首页 > 财经 > 金融 > Go单元测试

Go单元测试

2024/11/19 0:27:24 来源:https://blog.csdn.net/Ricardo2/article/details/140034868  浏览:    关键词: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遇到失败的用例会立即终止本次测试。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com