Go:C类似于编写测试代码的宏

时间:2014-09-29 09:22:03

标签: macros go

编写测试代码时,我做了很多这个

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中,失败的行号是错误的。

有解决方法吗?

3 个答案:

答案 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编码器都会立即识别出来。这就是重点。