Featured image of post Go 单元测试输出太乱?用 gotestsum 改善本地和 CI 体验

Go 单元测试输出太乱?用 gotestsum 改善本地和 CI 体验

gotestsum 不替代 go test,而是让测试结果更适合人读,也方便在 CI 中生成 JUnit 报告。

Go 自带的 go test ./... 足够好用,但项目包一多,输出就会变得有点难看。

尤其是在 CI 里,几十个包一起跑,真正失败的测试夹在一堆 ok 和日志中间,不太容易第一眼看到问题。

这时候 gotestsum 会舒服很多。

我第一次明显感觉到它有用,是 CI 里有个测试偶发失败,日志里前后混着很多包的输出。go test 不是不能看,但每次翻日志都要先定位失败包、失败用例、失败前后的输出。gotestsum 做的不是增强测试能力,而是把定位成本降下来。

它解决的是输出体验

gotestsum 本质上还是跑 go test,不是替代 Go 的测试框架。它主要做两件事:

  1. 整理测试输出,让成功、失败、跳过更清楚。
  2. 生成 CI 更容易消费的报告,比如 JUnit XML。

本地可以直接这样跑:

1
gotestsum -- ./...

注意 -- 后面的参数会传给 go test,所以原来的测试参数基本还能继续用。

比如只跑某个测试:

1
gotestsum -- -run TestCreateOrder ./...

加 race:

1
gotestsum -- -race ./...

在 CI 里生成 JUnit 报告

很多 CI 系统都能识别 JUnit XML。gotestsum 可以直接生成:

1
gotestsum --junitfile test-results.xml -- ./...

这样失败测试会在 CI 的测试报告里展示,不用每次去日志里慢慢翻。

如果项目有多个模块,也可以按模块分别输出报告,避免一个巨大文件不好定位。

我还会把普通测试和 CI 测试分开。普通测试追求快,CI 测试可以更严格:

1
2
3
gotestsum -- ./...

gotestsum --junitfile test-results.xml -- -race -count=1 ./...

-count=1 可以避免测试缓存干扰 CI 判断。不是每个项目都必须加,但排查偶发问题时很有用。

如果项目用 Makefile:

1
2
3
4
5
6
7
.PHONY: test test-ci

test:
	gotestsum -- ./...

test-ci:
	gotestsum --junitfile test-results.xml -- -race ./...

如果项目用 Taskfile:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
version: '3'

tasks:
  test:
    cmds:
      - gotestsum -- ./...

  test-ci:
    cmds:
      - gotestsum --junitfile test-results.xml -- -race ./...

本地默认命令不要太重,CI 命令可以加 -race、coverage 或报告输出。

不要让测试日志污染输出

gotestsum 能改善展示,但救不了测试里乱打日志的问题。

如果测试里大量 fmt.Println,CI 输出一样会很吵。我的习惯是:

  • 正常测试不要随便打印。
  • 调试信息用 t.Logf
  • 只有测试失败时再看详细上下文。
  • 集成测试和单元测试尽量分开。

工具只是把结果排得更清楚,测试本身还是要保持干净。

gotestsum 不是必须品,但它很适合中大型 Go 项目。它没有改变测试写法,也没有引入新的断言风格,只是让 go test 的结果更好读。

如果一个项目已经开始觉得 CI 测试日志难看,我会优先接入 gotestsum,而不是换测试框架。

参考资料

本文采用 CC BY-NC-SA 4.0 协议,转载请注明出处。
记录工程实践和排障过程。
使用 Hugo 构建
主题 StackJimmy 设计