如何包装Golang测试功能

6

我希望能够包装标准的 golang 测试函数,例如来自测试包的 t.Errorf

我尝试了以下方法:

// AssertEqual tests that the expected and actual values match
func AssertEqual(t *testing.T, expected interface{}, actual interface{}) {
    switch expected.(type) {
    case string:
        if expected != actual {
            t.Errorf("Error:\nexpected: %s\nactual: %s", expected, actual)
        }
    default:
        t.Errorf("Unsupported type")
    }
}

然而,当测试失败时,我会得到我的辅助函数的函数名和行号:
test_asserts.go:12: Error:
    expected: 
    actual: TestValue

有没有一种方法能够在调用方的行号上报告错误?


一年后,使用Go 1.9,添加t.Helper()将使行号变为正确的行号。请参见下面的答案 - VonC
3个回答

13

最近的 Go 1.9 (2017年8月) 版本中,您只需要在函数中添加一行代码:

t.Helper()

这将使错误报告中的该函数保持静默,您实际的错误行将是您期望的行(即调用此函数的行)。
请参见pkg/testing/#T.Helper(也可用于基准测试, 但不适用于TB接口,因为它被遗忘了!2021年2月:现在可用,请参见下文)。
// AssertEqual tests that the expected and actual values match
func AssertEqual(t *testing.T, expected interface{}, actual interface{}) {
    t.Helper()
    switch expected.(type) {
    case string:
        if expected != actual {
            t.Errorf("Error:\nexpected: %s\nactual: %s", expected, actual)
        }
    default:
        t.Errorf("Unsupported type")
    }
}

xuiqzy在2021年2月的评论中提到了某事,该评论涉及到了testing.TB接口,该接口现在具有Helper()功能。
请参见提交记录bc29313,2017年4月,go1.9beta1CL 38796以实现建议4899

我们建议添加一个新的testing.TB方法,Helper,用于标记调用函数为测试助手。 在记录测试消息时,testing包会忽略位于标记助手函数内部的帧。 它会打印第一个非助手函数内的堆栈位置。

现在TB接口也可用:https://golang.org/pkg/testing/#TB - xuiqzy
@xuiqzy 谢谢。我已经将您的评论包含在答案中以增加可见性。 - VonC

2
这是测试库的实现方式: https://golang.org/src/testing/testing.go?h=Errorf#L285 通过使用 runtime.Caller
你可以借鉴这段代码,自己编写一个能够查看更深层调用栈的错误函数。你可以替换整个 Errorf 函数(即 log + fail),或者不那么优美但更简单的方法是在调用 Errorf 之前使用类似 debug.PrintStack() 的函数打印整个调用栈。

0

您可以在assert包中看到Fail函数:https://github.com/stretchr/testify/blob/master/assert/assertions.go#L207

示例:

package main_test

import (
        "fmt"
        "github.com/stretchr/testify/assert"
        "strings"
        "testing"
)

// AssertEqual tests that the expected and actual values match
func AssertEqual(t *testing.T, expected interface{}, actual interface{}) {
        switch expected.(type) {
        case string:
                if expected != actual {
                        callInfo := assert.CallerInfo()
                        errorTrace := strings.Join(callInfo, "\n\r\t\t\t")
                        t.Errorf("\r%s\r\tError Trace:\t%s\n"+
                                "\r\tError:%s\n\r",
                                "",
                                errorTrace,
                                fmt.Sprintf("Error:\nexpected: %s\nactual: %s", expected, actual),
                        )
                }
        default:
                t.Errorf("Unsupported type")
        }
}                                                                                                                                                                                            

func TestFoo(t *testing.T) {                                                                                                                                                                 
        AssertEqual(t, "hello", 21)                                                                                                                                                          
}

结果:

$ go test main_test.go 
--- FAIL: TestFoo (0.00s)
        Error Trace::22:main_test.go:15
                        main_test.go:30
        Error:Error:
                expected: hello
                actual: %!s(int=21)

FAIL
FAIL    command-line-arguments  0.002s

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接