Go go test -json 怎样区分测试输出类型
来源:17golang原创
时间:2026-10-25 20:07:51 470浏览 收藏
go test -json 的测试输出应先看 Action:只有 output 事件才继续按 OutputType 分文本类别。空值是普通输出,frame 是测试框架文本,error 是 Error/Fatal 类报错,error-continue 表示多行报错的后续部分。测试最终是否失败仍看状态事件和测试命令退出码,不能由一条文字记录推断。
官方地址:https://go.dev/
如果要把测试报告做成一个小工具,我会先保留原始事件文件,再写分类器,而不是先用正则删除看起来多余的行。下面的项目只有一个命令行程序:读取标准输入,输出保留来源和原文的分类JSON。示例没有依赖第三方模块,代码和预期结果供读者复现,不展示为本机实测日志。
先确定分类器读取什么
测试事件包含状态信息和文本信息。Package 标明包,Test 在测试级事件中标明测试;包级事件可以没有 Test。并发运行时不能用“刚才出现的测试名”替代这两个字段。分类器给每条记录保留归属,避免不同测试的文字混在一起。
| 条件 | 分类器标签 | 用途 |
|---|---|---|
| Action 不是 output | status/原Action | 保留状态变化 |
| output 且 OutputType 为空 | text/regular | 普通日志展示 |
| OutputType 为 frame | text/frame | 框架文本可折叠 |
| OutputType 为 error | text/error | 突出报错正文 |
| OutputType 为 error-continue | text/error-continue | 保留报错连续内容 |
| 其他 OutputType | text/unknown:原值 | 未知格式仍不丢文本 |
这些 text/status 标签是本文程序定义的输出分类,不是 Go 工具链新增的官方字段。

保存一份测试事件流
在被测项目根目录保存事件文件。分类器源码请放在独立工具目录,避免给被测包引入额外 main 函数。以下命令使用 Bash,并分别保存测试状态与后续分类状态:
# 保存测试事件;stderr单独留存,避免混入JSON输入。
go test -json ./... > events.jsonl 2> test-stderr.log
test_rc=$?
# 测试失败也先完成报告分类,最后仍返回原来的失败状态。
go run /path/to/event-kind.go classified.jsonl
classify_rc=$?
if [ "$test_rc" -ne 0 ]; then
exit "$test_rc"
fi
exit "$classify_rc"把 /path/to/event-kind.go 换成自己的源码路径。上面的退出语句适合独立CI脚本。若在终端手动操作,可分开运行命令并查看状态变量,避免直接退出交互会话。不要加 2>&1 后就假设全部内容一定是JSON。
实现事件分类器
将下列内容保存为独立的 event-kind.go。使用 Decoder 连续解码对象,不要求输入是一整个JSON数组;使用 Encoder 输出分类记录,原文中的换行由JSON转义保留。
package main
import (
"encoding/json"
"errors"
"fmt"
"io"
"os"
)
type Event struct {
Action string
Package string
Test string
Output string
OutputType string
}
// kind 将事件状态与文本类别分开;未知类别保留给未来格式扩展。
func kind(e Event) string {
if e.Action != "output" {
return "status/" + e.Action
}
switch e.OutputType {
case "":
return "text/regular"
case "frame":
return "text/frame"
case "error":
return "text/error"
case "error-continue":
return "text/error-continue"
default:
return "text/unknown:" + e.OutputType
}
}
func main() {
dec := json.NewDecoder(os.Stdin)
out := json.NewEncoder(os.Stdout)
for {
var e Event
if err := dec.Decode(&e); err != nil {
if errors.Is(err, io.EOF) {
return // 正常读完输入,不把EOF当成坏数据。
}
fmt.Fprintln(os.Stderr, "事件JSON读取失败:", err)
os.Exit(1)
}
// 原文单独保留,避免日志中的换行破坏分类记录的边界。
row := struct {
Kind string
Package string
Test string
Action string
OutputType string
Output string
}{kind(e), e.Package, e.Test, e.Action, e.OutputType, e.Output}
if err := out.Encode(row); err != nil {
fmt.Fprintln(os.Stderr, "分类结果写入失败:", err)
os.Exit(1)
}
}
}结构体只声明分类所需字段;未声明的时间、耗时等不会进入这个精简报告。如需完整归档,应保留原始 events.jsonl,或者在程序中增加对应字段。遇到损坏JSON时程序停止并返回非零状态,防止一份不完整报告看起来像正常结束。
把分类结果接入CI
CI里建议同时上传原始事件、分类结果和独立的stderr文件。报告页面可以按 Kind 筛选,默认收起 text/frame,突出 text/error,同时显示 status/fail。不要因为一个包失败就将该包所有普通文本改标为 error。

多行错误聚合可以用 Package 与 Test 形成分组键,但不要假设相邻两条记录一定来自同一个测试。对第一版小工具,我更愿意保留每条事件,展示时按来源组织;如果确需拼接,仍应保留原记录顺序和原字段供追溯。
分类成功只表示输入已经被程序读取。若去掉前面脚本里的 test_rc 处理,测试失败后分类器却正常退出,CI就可能只看到最后一条命令成功。这是脚本状态传递的问题,不能靠搜索日志中的 FAIL 来替代。
用小样例理解边界
下面是手写的语义样例,用于理解字段组合;不是对某次测试完整事件序列的复制。把它保存为 sample.jsonl 后输入分类器:
{"Action":"output","Package":"demo/unit","Test":"TestNotice","OutputType":"frame","Output":"=== RUN TestNotice\n"}
{"Action":"output","Package":"demo/unit","Test":"TestNotice","Output":"ordinary notice\n"}
{"Action":"output","Package":"demo/unit","Test":"TestNotice","OutputType":"error","Output":"first error line\n"}
{"Action":"output","Package":"demo/unit","Test":"TestNotice","OutputType":"error-continue","Output":"second error line\n"}
{"Action":"fail","Package":"demo/unit","Test":"TestNotice"}五条记录应依次归入 text/frame、text/regular、text/error、text/error-continue、status/fail。JSON没有注释语法,所以字段说明放在代码块外;Output保存文本,OutputType只用于output事件的类别判断。
# 用手写样例查看分类器输出,不涉及运行被测项目。 go run /path/to/event-kind.go
为什么 OutputType 缺失不能等同于测试成功?
缺失或空值按普通输出处理,但整次测试仍可能在其他事件中失败。普通输出不是通过状态。
旧日志不含 OutputType 怎么办?
该程序会把output事件归为regular。它不会追溯识别以前日志的真实来源;需要细分时应使用明确支持该字段的工具链重新生成事件,而不是据此宣称旧记录没有报错。
能把所有 JSON 都交给这个程序吗?
本文面向测试事件,不能把其他构建工具或业务服务的JSON直接当作同一契约。即使能解码,字段缺失也会失去分类意义。
我的取舍是让小工具只做事件分类:原始文件负责留存,Action保留状态,OutputType区分文本,CI继续负责命令失败。职责明确后,折叠框架文本或突出报错都只影响展示。
官方资料:test2json输出格式;go命令说明。
-
123 收藏
-
350 收藏
-
110 收藏
-
499 收藏
-
141 收藏
-
312 收藏
-
465 收藏
-
262 收藏
-
485 收藏
-
501 收藏
-
462 收藏
-
240 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习