Go测试是什么_Go单元测试基本概念与使用说明

9次阅读

go测试是内置轻量级机制,需同包、_test.go文件、TestXxx签名;表驱动测试用结构体切片统一管理用例,配合t.Run定位失败项;go test常用-v、-run、-coverprofile等参数提升效率。

Go测试是什么_Go单元测试基本概念与使用说明

Go测试是内置在语言工具链里的轻量级验证机制,不是第三方库,也不需要配置文件或启动服务。它靠约定驱动:只要文件名以 _test.go 结尾、函数名以 Test 开头、参数是 *testing.Tgo test 就能自动发现并执行。

怎么写一个能跑起来的单元测试

最简路径就是三件事:同包、_test.go、TestXxx签名。别把测试文件扔到别的目录,也别用小写开头的函数名(比如 testAdd 不会被识别)。

  • 测试文件必须和被测代码在同一个包下,package mainpackage utils 都行,但不能改成 package test
  • 函数名必须是 Test + 首字母大写的单词,例如 TestAdd 合法,testAddTestadd 无效
  • 必须导入 "testing" 包,哪怕只用了一次 t.Error
  • 错误报告优先用 t.Errorf 而不是 paniclog.Fatal,否则测试框架无法统计失败数
package main  import "testing"  func Add(a, b int) int {     return a + b }  func TestAdd(t *testing.T) {     got := Add(2, 3)     want := 5     if got != want {         t.Errorf("Add(2,3) = %d, want %d", got, want)     } }

为什么表驱动测试比一 TestXxx 更实用

当你开始写 TestAddWithZeroTestAddWithNegativeTestAddoverflow……就该停手了。重复结构+相似逻辑=维护噩梦。表驱动把用例收进切片,一循环全跑完,加新 case 只改数据不改逻辑。

  • 每个测试项最好带 name 字段,出错时 t.Run(name, ...) 能准确定位哪条 case 挂了
  • 不要在循环里用 range tests 然后直接闭包引用 tc——所有子测试会共享最后一个值,要用 tc := tc 显式捕获
  • 边界值(0、负数、最大值)、空输入、错误返回,都塞进表里,比靠记忆补漏靠谱得多
func TestAddTableDriven(t *testing.T) {     tests := []struct {         name     string         a, b     int         expected int     }{         {"positive", 2, 3, 5},         {"zero", 0, 0, 0},         {"negative", -1, -1, -2},     }     for _, tc := range tests {         tc := tc // 防止闭包陷阱         t.Run(tc.name, func(t *testing.T) {             got := Add(tc.a, tc.b)             if got != tc.expected {                 t.Errorf("got %d, want %d", got, tc.expected)             }         })     } }

go test 命令常用参数不是摆设,而是日常刚需

go test 默认静默运行,失败才报错。但开发中你几乎每次都要加参数:查哪条失败、看覆盖率、单跑某个 case、确认是否真慢……不用白不用。

  • go test -v:必加。显示每个 TestXxx 的执行时间和 PASS/FAIL,没它等于盲测
  • go test -run ^TestAdd$:正则精确匹配,^$ 防止误中 TestAddWithZero
  • go test -coverprofile=cover.out && go tool cover -html=cover.out:生成 HTML 覆盖率报告,一眼看出哪些 if 分支根本没走
  • go test -timeout 5s:防止某个测试卡死,尤其涉及网络或 channel 等待的场景

真正容易被忽略的点是:测试函数里调用 t.Fatalt.Fatalf 会终止当前测试函数,但不会影响其他测试;而 t.Error 允许继续执行后续断言——这决定了你是想“一条失败全盘放弃”,还是“一次多验几个点”。选哪个,得看被测逻辑是否相互依赖。

text=ZqhQzanResources