ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
[TOC] ## **1.Go测试** Go语言中的测试依赖`go test`命名。在包目录内,所有以`_test.go`为后缀名的源代码文件都是`go test`测试的一部分,不会被`go build`编译到最终的可执行文件中。 在`*_test.go`文件中有三种类型的函数、单元测试函数、基准测试函数和示例函数。 | 类型 |格式 |作用 | | --- | --- |--- | | 测试函数 | 函数名前缀为Test | 测试程序的一些逻辑行为是否正确| | 基准函数 | 函数名前缀为Benchmark |测试函数的性能 | | 示例函数 | 函数名前缀为Example | 为文档提供示例文档| `go test`命令会遍历所有的`*_test.go`文件中符合上述命名规则的函数, 并生成一个临时的main包用于调用相应的测试函数, 然后构建并运行、报告测试结果,最后清理测试中生成的临时文件。 ~~~go func TestSplit(t *testing.T) { // 测试函数名必须以Test开头,必须接收一个*testing.T类型参数 got := Split("a:b:c", ":") // 程序输出的结果 want := []string{"a", "b", "c"} // 期望的结果 if !reflect.DeepEqual(want, got) { // 因为slice不能比较直接,借助反射包中的方法比较 t.Errorf("expected:%v, got:%v", want, got) // 测试失败输出错误提示 } } func TestMoreSplit(t *testing.T) { got := Split("abcd", "bc") want := []string{"a", "d"} if !reflect.DeepEqual(want, got) { t.Errorf("expected:%v, got:%v", want, got) } } ~~~ ``` go test // 执行 test文件 go test -v // 查看测试函数名称和运行时间 go test -v -run="more" //-run参数对应正则表达式。 ``` ## **2.单元测试函数** 每个测试函数必须导入 `testing` 包,测试函数的基本格式(签名)如下: ~~~go func TestName(t *testing.T){ // ... } ~~~ 测试函数的命名必须以`Test`开头。 ``` // 其中 t 用于报告测试失败和附加的日志信息。 func TestAdd(t *testing.T){ ... } func TestSum(t *testing.T){ ... } func TestLog(t *testing.T){ ... } ``` `go test`:在某一路径下执行该命令,会运行该目录下所有*_test.go文件。 `go test -v`:输出完整的测试结果,能更好地在输出结果中看到每个测试用例执行情况。 `go test -run=reg -v`:`-run`参数对应一个正则,只有函数名匹配上的测试函数才会被执行。 ## **3.跳过某些测试** 为了节省时间支持在单元测试时跳过某些耗时的测试用例。 ``` func TestTimeConsuming(t *testing.T) { if testing.Short() { t.Skip("short模式下会跳过该测试用例") } ... } ``` 当执行`go test -short`时就不会执行上面的`TestTimeConsuming`测试用例。 ## **4.子测试** 在Go1.7+新增了子测试,支持在测试函数中使用`t.Run`执行一组测试用例,这样就不需要为不同的测试数据定义多个测试函数了。 ~~~go func TestXXX(t *testing.T){ t.Run("case1", func(t *testing.T){...}) t.Run("case2", func(t *testing.T){...}) t.Run("case3", func(t *testing.T){...}) } ~~~ ## **5.表格驱动测试** 表格驱动测试不是工具、包或其他任何东西,它只是编写更清晰测试的一种方式和视角。 表格驱动测试可以涵盖很多方面:表格里的每一个条目都是一个完整的测试用例,包含输入和预期结果,有时还包含测试名称等附加信息,以便于输出易于阅读。 使用表格驱动测试能够很方便的维护多个测试用例,避免在编写单元测试时频繁的复制粘贴。 ## **6.并行测试** 在单元测试过程中使用并行测试,通过添加`t.Parallel()`来实现。 ## **7.使用工具生成测试代码** gotests可以快速生成测试文件。 ``` go get -u github.com/cweill/gotests/... gotests -all -w split.go ``` ## **8.测试覆盖率** 测试覆盖率指代码被测试套件覆盖的百分比。 Go提供内置功能来检查你的代码覆盖率,`go test -cover`来查看测试覆盖率。 ![](https://img.kancloud.cn/8c/7a/8c7a13f6fcf2f549791b9f998257ba4a_578x123.png) Go还提供`-coverprofile`参数,用来将覆盖率相关的记录信息输出到一个文件。 ``` go test -cover -coverprofile=c.out ``` 然后可以执行`go tool cover -html=c.out`,使用`cover`工具来处理生成的记录信息,该命令会打开本地的浏览器窗口生成一个HTML报告。 ## **9.testify/assert** testify是一个流行的Go单元测试工具包,其中使用最多的功能就是它提供的断言工具——`testify/assert`或`testify/require`。 **安装** ``` go get github.com/stretchr/testify ``` 在写单元测试时,通常需要使用断言来校验测试结果,由于Go官方没有提供断言,就会写很多if...eles语句。而`testify/assert`为我们提供了很多常用的断言函数,并且能够输出友好、易于阅读的错误描述信息。 ``` t.Run(tt.name, func(t *testing.T) { // 使用t.Run()执行子测试 got := Split(tt.input, tt.sep) if !reflect.DeepEqual(got, tt.want) { t.Errorf("expected:%#v, got:%#v", tt.want, got) } }) // 简化 t.Run(tt.name, func(t *testing.T) { // 使用t.Run()执行子测试 got := Split(tt.input, tt.sep) assert.Equal(t, got, tt.want) // 使用assert提供的断言函数 }) ``` 当有多个断言语句时,可以使用`assert := assert.New(t)`创建一个assert对象,它拥有前面所有的断言方法,只是不需要再传入`Testing.T`参数了。