Go—工程测试| 青训营笔记

53 阅读3分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 2 天


这是我参与「第五届青训营 」伴学笔记创作活动的第 2 天

Part1 单元测试

单元测试(Unit Tests, UT) 是一个优秀项目不可或缺的一部分,特别是在一些频繁变动和多人合作开发的项目中尤为重要。

  1. 你或多或少都会有因为自己的提交,导致应用挂掉或服务宕机的经历。如果这个时候你的修改导致测试用例失败,你再重新审视自己的修改,发现之前的修改还有一些特殊场景没有包含,恭喜你减少了一次上库失误。 -- 减少出错
  2. 项目很大,启动环境很复杂,你优化了一个函数的性能,或是添加了某个新的特性,如果部署在正式环境上之后再进行测试,成本太高。对于这种场景,几个小小的测试用例或许就能够覆盖大部分的测试场景。 -- 降低成本
  3. 而且在开发过程中,效率最高的莫过于所见即所得了,单元测试也能够帮助你做到这一点,试想一下,假如你一口气写完一千行代码,debug 的过程也不会轻松,如果在这个过程中,对于一些逻辑较为复杂的函数,同时添加一些测试用例,即时确保正确性,最后集成的时候,会是另外一番体验。 -- 增加上线自信

接下来将介绍如何使用 Go 语言的标准库 testing 进行单元测试。

1. 文件命名:

   Go 语言推荐测试文件和源代码文件放在一块,测试文件以 `_test.go` 结尾。如图:为了测试`PassLine.go`中的某一个函数我们应该在同等的目录下 新建测试文件 `PassLine_test.go` 这样非常有利于我们观察和处理文件

1000.png

2.函数命名以及测试函数的命名规则:

   我们在代码文件中 有函数命名为`PassLine(x int)bool`

选区_003.png 选区_004.png

  1. 测试用例名称一般命名为 Test 加上待测试的方法名。
  2. 测试用的参数有且只有一个,在这里是 t *testing.T
  3. 基准测试(benchmark)的参数是 *testing.B,TestMain 的参数是 *testing.M 类型。

3.测试启动的方法

运行
    go test 测试运行
    go test -v参数会显示每个用例的测试结果
    go test -v -cover 可以查看覆盖率。
如果只想运行其中的一个用例,例如 `TestAdd`,可以用 `-run` 参数指定,该参数支持通配符 `*`,和部分正则表达式,例如 `^``$`

选区_005.png

Part2 Mock测试

mock/stub 测试,当待测试的函数/对象的依赖关系很复杂,并且有些依赖不能直接创建,例如数据库连接、文件I/O等。这种场景就非常适合使用 mock/stub 测试。简单来说,就是用 mock 对象模拟依赖项的行为

简单来说当我们的测试对一些文件,数据库之类的产生了强依赖 那么我们的文件修改了 测试也就自然失效了

https://github.com/bouk/monkey下载一个mock mock实现的原理就是篡改函数调用的指针 当我们调用目标函数的时候会重定向指向我们指定的新函数 从而屏蔽掉文件的影响去对上层进行验证

monkey.Patch(xx原函数 , xx目标函数)替换 monkey.Unpatch(xx 原函数) 恢复

Part3 基准测试

基准测试用例的定义如下:

func BenchmarkXxx(b *testing.B){
    // ...
}
  • 函数名必须以 Benchmark 开头,后面一般跟待测试的函数名
  • 参数为 b *testing.B
  • 执行基准测试时,需要添加 -bench 参数。
  • -benchmem 参数可以度量内存分配的次数。
  • $ go test -benchmem -bench .运行语句

例如:

func BenchmarkHello(b *testing.B) {
    for i := 0; i < b.N; i++ {
        XXX测试函数
    }
}

如果在运行前基准测试需要一些耗时的配置,则可以使用 b.ResetTimer() 先重置定时器以达到局部测试时间

func BenchmarkXXX(b *testing.B) {
    ... // 耗时操作
    b.ResetTimer()
    for i := 0; i < b.N; i++ {
       xxx测试函数
    }
}

使用 RunParallel 测试并发性能

func BenchmarkXXXParallel(b *testing.B) {
	b.RunParallel(func(pb *testing.PB) {
		for pb.Next() {
			// 所有 goroutine 一起,循环一共执行 b.N 次
			xxx测试函数
		}
	})
}

参考材料: [极客兔兔]

码风略丑 读者见谅 --2023/1/16