模块 9 · 第 1 课(共 5)课程中的41/50~12 min
模块课程(1/5)
“测试”包
在 Go 中,测试是 stdlib 的一部分*_:没有外部库,没有要配置的框架。您所需要的只是代码旁边的 _\_test.go文件、一些TestXxx函数和go test 命令。
基本约定
- 测试文件被命名为
<something>_test.go,并且与它们测试的代码位于相同的包中(或者位于<name>_test包中以进行“黑盒测试”)。 - 测试函数有一个精确的签名:
func TestXxx(t *testing.T),其中Xxx以大写字母开头。 - 您从 stdlib 导入
testing。 - 否
assertEquals:您将if got != want { t.Errorf(...) }与fmt动词一起使用。
Go
// math.go
package math
func Sum(a, b int) int { return a + b }
// math_test.go
package math
import "testing"
func TestSum(t *testing.T) {
got := Sum(2, 3)
if got != 5 {
t.Errorf("Sum(2,3) = %d; voglio %d", got, 5)
}
}运行它:
Bash
go test ./... # all packages in the module
go test -v ./pkg # verbose: prints test names
go test -run TestSum # only tests matching the regext.Error 与 t.Fatal
这是表示失败的两个基本动词:
| 方法 | 效果 |
|---|---|
t.Log(args...) | 记录但不会失败(仅在使用 -v 或失败时可见)。 |
t.Error(args...) | 记录、标记“失败”、继续测试功能。 |
t.Errorf(fmt, ...) | 就像带有格式的 Error 一样。 |
t.Fatal(args...) | 记录、标记“失败”、停止测试(调用 runtime.Goexit)。 |
t.Fatalf(fmt, ...) | t.Fatalf(fmt, ...)就像带有格式的 Fatal 一样。 |
经验法则:当继续没有意义时使用 Fatal (例如,设置失败、即将发生 nil 指针取消引用);否则**Error**,它可以让您在单次运行中查看所有失败。
Go
func TestOpen(t *testing.T) {
f, err := os.Open("fixtures/sample.txt")
if err != nil {
t.Fatal(err) // if it doesn't open, the next steps would fail on nil
}
defer f.Close()
// ... assert on content with t.Errorf
}使用 t.Cleanup 设置和拆卸
要在测试(或子测试)结束时释放资源,请使用 t.Cleanup 而不是 defer:
Go
func TestDB(t *testing.T) {
db := newTestDB(t)
t.Cleanup(func() { db.Close() })
// ... test
}相对于 defer 的优点:创建 db 的帮助程序可以内部注册清理,因此调用者不需要记住它。
测试助手
t.Helper() 方法将函数标记为“助手”:当测试失败时,堆栈跟踪跳过助手函数并直接指向调用者:
Go
func mustParseInt(t *testing.T, s string) int {
t.Helper()
n, err := strconv.Atoi(s)
if err != nil {
t.Fatalf("parse %q: %v", s, err)
}
return n
}练习
锻炼#go.m9.l1.e1
尝试:0加载中...
定义 TestSum 函数,使用 t.Errorf 和格式化消息来验证 Sum(2,3) == 5。
正在加载编辑器...
3 次尝试后可用的解决方案
锻炼#go.m9.l1.e2
尝试:0加载中...
在 TestDiv 中,如果 Div 返回意外值,请使用 t.Fatal 立即停止测试。
正在加载编辑器...
3 次尝试后可用的解决方案
Quiz#go.m9.l1.e3
准备好t.Error 和 t.Fatal 之间的根本区别是什么?
Go
if err != nil {
t.???(err)
}