编写测试代码时,我做了很多这个
if (!cond) {
t.Fatal("error message")
}
这有点单调乏味。所以我想实现以下目标
CHECK(cond, "error message")
所以我尝试了这个
func CHECK(t *testing.T, cond bool, fmt string, a ...interface{}) {
if !cond {
t.Fatal(fmt, a)
}
}
如果它是一个C宏,它将完美地工作。但在Go中,失败的行号是错误的。
有解决方法吗?
答案 0 :(得分:1)
可悲的是,你无法做到。
解决方法是自己获取行/函数,类似于https://stackoverflow.com/a/25954534/145587中的跟踪函数。
答案 1 :(得分:1)
您可以使用runtime.Callers()
+ runtime.Caller()
:第一个允许您调用堆栈,而第二个允许提取有关任意堆栈帧(从该列表中获取)的调试信息。
你的CHECK()
函数总是一个函数调用,如果它是一个宏,检查应该发生在哪里,所以你可以检查上面的堆栈帧。
更新:真正需要的唯一功能是runtime.Caller()
。这是你的情况,简化:
package main
import (
"runtime"
"testing"
)
func CHECK(t *testing.T, cond bool) {
if !cond {
_, fname, lineno, ok := runtime.Caller(1)
if !ok {
fname, lineno = "<UNKNOWN>", -1
}
t.Fatalf("FAIL: %s:%d", fname, lineno)
}
}
func TestFoo(t *testing.T) {
CHECK(t, 12 == 13)
}
保存为check_test.go
并通过go test
运行时,会生成:
$ go test
--- FAIL: TestFoo (0.00 seconds)
check_test.go:14: FAIL: /home/kostix/devel/go/src/check/check_test.go:19
FAIL
exit status 1
FAIL check 0.001s
第19行是CHECK()
的调用位于TestFoo()
内的行。
答案 2 :(得分:0)
虽然上面使用CHECK()函数的答案都可行,但我认为实际答案是代码可读性。 Go的大部分内容都是为了提高整个社区的可读性而设计的。例如,请参阅gofmt。大多数人都会同意,它的格式并不适用于所有情况。但是,让所有人同意的公约对Go来说是一个巨大的优势。同样的答案是你的问题。 Go是为同行编写代码,而不是为自己编写代码。所以不要想#34;我更喜欢这个。&#34;想一想,阅读我的代码的人会理解什么。&#34;
您的原始代码应该是这样的,没有括号。
if !cond {
t.Fatal("error message")
}
这是惯用的,每个Go编码器都会立即识别出来。这就是重点。