Go 编程实例【测试】

系统管理员 2023-10-08 23:08 70阅读 0赞

阅读目录

  • 基础实例
  • 组织你的单元测试代码
  • 关于 go testing 启动命令

基础实例

想要写出好的 Go 程序,单元测试是很重要的一部分。

testing 包为提供了编写单元测试所需的工具,写好单元测试后,我们可以通过 go test 命令运行测试。

为方便演示,例子的代码位于 main 包,实际上,单元测试的代码可以位于任何包下。

测试代码通常与需要被测试的代码位于同一个包下。

  1. // main_test.go
  2. package main
  3. import (
  4. "fmt"
  5. "testing"
  6. )
  7. // 我们要测试下面这个简单的函数——返回最小值。
  8. // 一般地,需要被测试的代码应该在类似于 `intutils.go` 的文件下,
  9. // 其对应的测试文件应该被命名为 `intutils_test.go`。
  10. func IntMin(a, b int) int {
  11. if a < b {
  12. return a
  13. } else {
  14. return b
  15. }
  16. }
  17. // 通常编写一个名称以 `Test` 开头的函数来创建测试。
  18. func TestIntMinBasic(t *testing.T) {
  19. ans := IntMin(2, -2)
  20. if ans != -2 {
  21. // `t.Error*` 会报告测试失败的信息,然后继续运行测试。
  22. // `t.Fail*` 会报告测试失败的信息,然后立即终止测试。
  23. t.Errorf("IntMin(2, -2) = %d; want -2", ans)
  24. }
  25. }
  26. // 单元测试可以重复,所以会经常使用 *表驱动* 风格编写单元测试,
  27. // 表中列出了输入数据,预期输出,使用循环,遍历并执行测试逻辑。
  28. func TestIntMinTableDriven(t *testing.T) {
  29. var tests = []struct {
  30. a, b int
  31. want int
  32. }{
  33. {
  34. 0, 1, 0},
  35. {
  36. 1, 0, 0},
  37. {
  38. 2, -2, -2},
  39. {
  40. 0, -1, -1},
  41. {
  42. -1, 0, -1},
  43. }
  44. for _, tt := range tests {
  45. // t.Run 可以运行一个 "subtests" 子测试,一个子测试对应表中一行数据。
  46. // 运行 `go test -v` 时,他们会分开显示。
  47. testname := fmt.Sprintf("%d,%d", tt.a, tt.b)
  48. t.Run(testname, func(t *testing.T) {
  49. ans := IntMin(tt.a, tt.b)
  50. if ans != tt.want {
  51. t.Errorf("got %d, want %d", ans, tt.want)
  52. }
  53. })
  54. }
  55. }

使用 -v 参数查看详细信息:

  1. [root@bogon test]# go test -v
  2. === RUN TestIntMinBasic
  3. --- PASS: TestIntMinBasic (0.00s)
  4. === RUN TestIntMinTableDriven
  5. === RUN TestIntMinTableDriven/0,1
  6. === RUN TestIntMinTableDriven/1,0
  7. === RUN TestIntMinTableDriven/2,-2
  8. === RUN TestIntMinTableDriven/0,-1
  9. === RUN TestIntMinTableDriven/-1,0
  10. --- PASS: TestIntMinTableDriven (0.00s)
  11. --- PASS: TestIntMinTableDriven/0,1 (0.00s)
  12. --- PASS: TestIntMinTableDriven/1,0 (0.00s)
  13. --- PASS: TestIntMinTableDriven/2,-2 (0.00s)
  14. --- PASS: TestIntMinTableDriven/0,-1 (0.00s)
  15. --- PASS: TestIntMinTableDriven/-1,0 (0.00s)
  16. PASS
  17. ok test 0.002s
  18. [root@bogon test]#

组织你的单元测试代码

  • 测试代码文件名 xxx_test.go,必须遵守。
  • 测试函数签名 TestXXX(t *testing.T),必须遵守。
  • 测试文件所在包,不强制。可以与对应的功能代码文件位于同一个包,开发者根据自己的需要来确定工程规范。

为了更好的管理单元测试代码,按照 go testing 的命名规范,运行 go testing 会扫描并编译运行工程目录下 xxx_test.go 代码文件中的 TestXXX 测试函数。对一个没有任何测试代码的 go 程序工程运行 go testing 只会提示 no tests to run 并不会报错。

不用担心这些测试代码管理会让你的代码工程变得混乱,你可以使用一个专门的工程级目录(比如叫 test) 来存放所有主要的测试代码。也可以在对应的包(比如 app)下使用对应测试包(比如 app_test)。这样就可以利用人为区分,用何种目录方式完全取决于你的需要。但这对于 go 工具链来说不是必要的,因为它并不会把这些测试代码打包到程序的发行版本中。

关于 go testing 启动命令

在上面的例子中,单元测试用例的启动都是使用 go test 来启动的,关于这个命令,有必要说明的地方。

go test .
仅从当前目录查找 xxx_test.go 测试代码。

go test ./...
找出当前的目录以及子目录下所的 xxx_test.go 测试代码。

go test ./xxx/xxx
找出路径下的 xxx_test.go 测试代码,如果包含子目录,使用 ./xxx/xxx/...,即在路径后加上 /...,注意,是 3 个 “.” 号。

go test 路径 -v
-v 参数,打开终端信息打印的开关。
在没有 -v 选项时,测试代码中的打印函数(t.Log、t.Skip、t.Error、t.Fatal)向终端打印的信息,只有测试函数状态为 FAIL 的才会显示。而 fmt.Print 只会在任一测试函数为 FAIL 时,信息才会显示。所以在调试单元测试代码时,通常会使用 -v 参数,可多次成功执行的,不带 -v,以保持终端信息提示的清晰。

这只是实践建议,是否使用取决于你。

go test -run ^TestXXXX$
-run 用来指定执行某个 TestXXX 单元测试函数,支持使用正则表达式来匹配测试函数名称。当然,像 TestMain、init() 这类框架性代码仍然会被执行,以确保环境正确。

发表评论

表情:
评论列表 (有 0 条评论,70人围观)

还没有评论,来说两句吧...

相关阅读

    相关 Go 编程实例【math】

    阅读目录 说明 Sqrt 函数计算一个数的平方根 说明 math是Go标准库中的一个包,提供了数学运算相关的函数和常量。 它包含了很多常用的数