包装 testing.T.Errorf() 时显示原始源代码行
Show original source line when wrapping testing.T.Errorf()
我正在为 Go 模块编写一些测试。其中很多是检查函数 return 的正确值。这是我目前正在做的一个简单示例:
package foo
import (
"reflect"
"testing"
)
func Foo() int {
return 3
}
func TestFoo(t *testing.T) {
expected := 4
actual := Foo()
if !reflect.DeepEqual(actual, expected) {
t.Errorf("actual=%v, expected=%v", actual, expected)
}
}
一个测试可能包含许多这样的相等性检查。为每个检查重复这 6 行使得测试难以阅读并且容易出错(根据我过去几天的经验)。所以我想我会做一个 assertEquals()
函数来包装整个逻辑,类似于其他测试框架提供的(例如 JUnit's org.junit.Assert
):
func TestFoo(t *testing.T) {
assertEqual(t, 4, Foo())
}
func assertEqual(t *testing.T, actual interface{}, expected interface{}) {
if !reflect.DeepEqual(actual, expected) {
t.Errorf("Assertion failed: %v != %v", actual, expected)
}
}
现在的问题是Errorf()
显然不会显示调用assertEqual()
的行,而是显示assertEqual
内部对Errorf()
的调用:
=== RUN TestFoo
foo_test.go:28: Assertion failed: 4 != 3
--- FAIL: TestFoo (0.00s)
有没有办法解决这个问题,例如通过显示整个堆栈跟踪而不是仅显示对 Errorf()
?
的调用位置
或者是否有更好的方法来避免重复这些代码行来检查函数的 return 值?
您可以使用 t.Helper()
:
Helper marks the calling function as a test helper function. When printing file and line information, that function will be skipped. Helper may be called simultaneously from multiple goroutines.
因此您的辅助函数变为:
func assertEqual(t *testing.T, actual interface{}, expected interface{}) {
t.Helper()
if !reflect.DeepEqual(actual, expected) {
t.Errorf("Assertion failed: %v != %v", actual, expected)
}
}
输出:
=== RUN TestFoo
prog.go:13: Assertion failed: 4 != 3
--- FAIL: TestFoo (0.00s)
FAIL
其中 this playground 中的 prog.go:13
是主要测试目标 中调用 assertEqual
而不是 t.Errorf
的行它。
这只会更改测试输出中的文件行。如果你真的想要完整的堆栈跟踪,你可以使用 runtime.Caller
中提到的 threads.
我正在为 Go 模块编写一些测试。其中很多是检查函数 return 的正确值。这是我目前正在做的一个简单示例:
package foo
import (
"reflect"
"testing"
)
func Foo() int {
return 3
}
func TestFoo(t *testing.T) {
expected := 4
actual := Foo()
if !reflect.DeepEqual(actual, expected) {
t.Errorf("actual=%v, expected=%v", actual, expected)
}
}
一个测试可能包含许多这样的相等性检查。为每个检查重复这 6 行使得测试难以阅读并且容易出错(根据我过去几天的经验)。所以我想我会做一个 assertEquals()
函数来包装整个逻辑,类似于其他测试框架提供的(例如 JUnit's org.junit.Assert
):
func TestFoo(t *testing.T) {
assertEqual(t, 4, Foo())
}
func assertEqual(t *testing.T, actual interface{}, expected interface{}) {
if !reflect.DeepEqual(actual, expected) {
t.Errorf("Assertion failed: %v != %v", actual, expected)
}
}
现在的问题是Errorf()
显然不会显示调用assertEqual()
的行,而是显示assertEqual
内部对Errorf()
的调用:
=== RUN TestFoo
foo_test.go:28: Assertion failed: 4 != 3
--- FAIL: TestFoo (0.00s)
有没有办法解决这个问题,例如通过显示整个堆栈跟踪而不是仅显示对 Errorf()
?
或者是否有更好的方法来避免重复这些代码行来检查函数的 return 值?
您可以使用 t.Helper()
:
Helper marks the calling function as a test helper function. When printing file and line information, that function will be skipped. Helper may be called simultaneously from multiple goroutines.
因此您的辅助函数变为:
func assertEqual(t *testing.T, actual interface{}, expected interface{}) {
t.Helper()
if !reflect.DeepEqual(actual, expected) {
t.Errorf("Assertion failed: %v != %v", actual, expected)
}
}
输出:
=== RUN TestFoo
prog.go:13: Assertion failed: 4 != 3
--- FAIL: TestFoo (0.00s)
FAIL
其中 this playground 中的 prog.go:13
是主要测试目标 中调用 assertEqual
而不是 t.Errorf
的行它。
这只会更改测试输出中的文件行。如果你真的想要完整的堆栈跟踪,你可以使用 runtime.Caller
中提到的