写点什么

Go 语言,测试功能详解 - 上

作者:微客鸟窝
  • 2021 年 11 月 15 日
  • 本文字数:2537 字

    阅读完需:约 8 分钟

Go语言,测试功能详解-上

目前 Go 测试系统支持单元测试、性能测试和示例测试:

  • 单元测试:单元测试是指对软件中的最小可测试单元进行检查和验证

  • 性能测试:性能测试,也称基准测试,是测量一个程序在固定工作负载下的性能。

  • 示例测试:广泛应用于 Go 源码和各种开源框架中,用于展示某个包或某个方法的用法。

单元测试

单元测试就是对单元进行测试,一个单元可以是一个函数、一个模块等。

目录结构如下所示:

[ceshi]      |--[gotest]                  |--unit.go      |--[gotest_test]                  |--unit_test.go
复制代码

unit.go 为源代码文件, unit_test.go 为测试文件。测试文件必须以“_test.go”结尾。

源代码文件 unit.go 代码:

package gotestfunc Add(a, b int) int { return a + b}
复制代码

测试文件 unit_test.go 代码:

package gotest_testimport ( "ceshi/gotest" "testing")func TestAdd(t *testing.T){ var a = 1 var b = 2 var expected = 3 actual := gotest.Add(a, b) if actual != expected {  t.Errorf("Add(%d, %d) = %d; expected: %d", a, b, actual, expected) }}
复制代码

测试文件可以跟源文件在同一个包,但多数情况是创建一个包专用于测试,这样可以使测试文件和源文件隔离。GO 源代码以及其他知名的开源框架通常会创建测试包,而且规则是在原包名上加上”_test”。

执行测试

在测试文件所在目录中,使用 go test 命令即可启动单元测试,如下所示:

$ go testPASSok      ceshi/gotest_test       0.818s
复制代码

单元测试规则:

  1. 单元测试的 go 文件必须以 _test.go 结尾,Go 语言测试工具只认符合这个规则的文件。

  2. 单元测试文件名 _test.go 前面的部分最好是被测试的函数所在的 go 文件的文件名。

  3. 单元测试的函数名必须以 Test 开头,是可导出的、公开的函数。

  4. 测试函数的签名必须接收一个指向 testing.T 类型的指针,且不能返回任何值。

  5. 函数名最好是 Test + 被测试的函数名。

性能测试(基准测试)

基准测试函数和普通测试函数写法类似,但是以Benchmark为前缀名,并且带有一个*testing.B类型的参数;*testing.B参数除了提供和*testing.T类似的方法,还有额外一些和性能测量相关的方法。它还提供了一个整数 N,用于指定操作执行的循环次数。

目录结构如下所示:

[ceshi]  |--[gotest]          |--benchmark.go  |--[gotest_test]          |--benchmark_test.go
复制代码

benchmark.go 为源代码文件, benchmark_test.go 为测试文件。

源代码文件 benchmark.go 代码:

package gotest
//不预分配func Slice1() []int { var newSlice []int for i := 0; i < 100000; i++ { newSlice = append(newSlice, i) } return newSlice}
//预分配Slice的存储空间构造func Slice2() []int { var newSlice []int newSlice = make([]int, 0, 100000) for i := 0; i < 100000; i++ { newSlice = append(newSlice, i) }
return newSlice}
复制代码

两个方法都构造一个容量 100000 的切片,所不同的是 Slice1() 不预先分配内存, Slice2() 会预先分配内存,本次来测试一下二者的性能差异。

测试文件 benchmark_test.go 代码:

package gotest_testimport ( "ceshi/gotest" "testing")
func BenchmarkSlice1(b *testing.B) { for i := 0; i < b.N; i++ { gotest.Slice1() }}
func BenchmarkSlice2(b *testing.B) { for i := 0; i < b.N; i++ { gotest.Slice2() }}
复制代码

执行测试

$ go test -bench=.goos: windowsgoarch: amd64pkg: ceshi/gotest_testcpu: Intel(R) Core(TM) i7-10750H CPU @ 2.60GHz
BenchmarkSlice1-12 2539 474179 ns/opBenchmarkSlice2-12 10000 109779 ns/opPASSok ceshi/gotest_test 4.018s
复制代码

其中 -bench 为 go test 的 flag,该 flag 指示 go test 进行性能测试。通过输出可以直观的看出, BenchmarkSlice1 执行了 2539 次,平均每次 474179 纳秒, BenchmarkSlice2 执行了 10000 次,平均每次 109779 纳秒。从测试结果上看,虽然构造切片很快,但通过给切片预分配内存,性能还可以进一步提升,符合预期。

性能测试规则:

  1. 文件名必须以“_test.go”结尾;

  2. 函数名必须以“Benchmark”开始;

  3. 使用命令“go test -bench=.”开始性能测试;

示例测试

目录结构如下所示:

[ceshi]  |--[gotest]          |--example.go  |--[gotest_test]          |---example_test.go
复制代码

example.go 为源代码文件, example_test.go 为测试文件。

源代码文件 example.go 代码:

package gotestimport "fmt"
//一行打印输出func SayHello() { fmt.Println("Hello 微客鸟窝")}
//两行打印输出func SayGoodbye() { fmt.Println("微客鸟窝,") fmt.Println("goodbye")}
//多行打印输出,由于Map数据结构的原因,多行打印次序是随机的。func PrintName() { name := make(map[int]string, 4) name[1] = "微" name[2] = "客" name[3] = "鸟" name[4] = "窝" for _, value := range name { fmt.Println(value) }}
复制代码

测试文件 example_test.go 代码:

package gotest_testimport "ceshi/gotest"func ExampleSayHello() { gotest.SayHello() // OutPut: Hello 微客鸟窝}
func ExampleSayGoodbye() { gotest.SayGoodbye() // OutPut: // 微客鸟窝, // goodbye}
func ExamplePrintName() { gotest.PrintName() //Unordered output: //微 //客 //鸟 //窝}
复制代码

例子测试函数命名规则为”Examplexxx”,其中”xxx”为自定义的标识,通常为待测函数名称。

执行测试

$ go test example_test.gook      command-line-arguments  0.605s
复制代码

示例测试规则:

  1. 例子测试函数名需要以”Example”开头;

  2. 检测单行输出格式为“// Output: <期望字符串>”;

  3. 检测多行输出格式为“// Output: \ <期望字符串> \ <期望字符串>”,每个期望字符串占一行;

  4. 检测无序输出格式为”// Unordered output: \ <期望字符串> \ <期望字符串>”,每个期望字符串占一行;

  5. 测试字符串时会自动忽略字符串前后的空白字符;

  6. 如果测试函数中没有“Output”标识,则该测试函数不会被执行;

  7. 执行测试可以使用 go test ,此时该目录下的其他测试文件也会一并执行;

  8. 执行测试可以使用 go test <xxx_test.go> ,此时仅执行特定文件中的测试函数;

用户头像

微客鸟窝

关注

还未添加个人签名 2019.11.01 加入

公众号《微客鸟窝》笔者,目前从事web后端开发,涉及语言PHP、golang。获得美国《时代周刊》2006年度风云人物!

评论

发布
暂无评论
Go语言,测试功能详解-上