如何修复Go测试输出中的行号?

Kos*_*Kos 10 testing go

让我们考虑一下这个简单的测试代码.

(注意:assertSomething这里非常简单,但通常我会为手头的任务编写一个更专业的帮助程序,它会查看多个内容并报告多种类型的错误.)

package hello

import "testing"

func TestFoo(t *testing.T) {
    assertSomething(t, 2+2 == 4) // line 6
    assertSomething(t, 2+3 == 6) // line 7
}

func assertSomething(t *testing.T, expected bool) {
    if !expected {
        t.Error("Something's not right") // line 12
    }
}
Run Code Online (Sandbox Code Playgroud)

当我跑步时go test,我得到以下内容:

--- FAIL: TestFoo (0.00s)
    hello.go:12: Something's not right
FAIL
exit status 1
FAIL    kos/hello   0.008s
Run Code Online (Sandbox Code Playgroud)

我有两个问题:

1)错误指向第12行 - 为什么?如何t.Error找出它的调用方式?

2)在帮助程序中,我想指定t.Error应该查看堆栈级别更高以确定要打印的行号,以便我得到这样的消息:

--- FAIL: TestFoo (0.00s)
    hello.go:7: Something's not right
Run Code Online (Sandbox Code Playgroud)

Python允许我这样做,例如,warnings.warn("message", stacklevel=2)- 我将如何在这里实现等价物?

Pau*_*kin 12

你可以做你想要的,你可以t.Error通过查看源代码了解它是如何工作的.decorate我认为这个功能正是你要找的.

但是,如果您有大量的检查代码,并且由于某种原因它在测试中变得重复,最好将其作为返回错误的函数提取而不是通过测试.并使其成为"断言" ".实际上,在语言FAQ中明确不鼓励编写断言函数.

package hello

import "testing"

func TestFoo(t *testing.T) {
    if err := checkSomething(2+2 == 4); err != nil {
        t.Errorf("2+2=4 failed: %s", err)
    }
    if err := checkSomething(2+3 == 6); err != nil {
        t.Errorf("2+3=6 failed: %s", err)
    }
}

func checkSomething(v bool) error {
    if !v {
        return errors.New("something's not right")
    }
    return nil
}
Run Code Online (Sandbox Code Playgroud)

但这就是我认为惯用测试代码的样子.它是由表驱动的,案例包括输入和预期输出,在测试失败时导致非常清晰的错误消息.

package hello

import "testing"

func TestFoo(t *testing.T) {
    cases := []struct {
        a, b, want int
    }{
        {2, 2, 4},
        {2, 3, 6},
    }
    for _, c := range cases {
        if got := operation(c.a, c.b); got != c.want {
            t.Errorf("operation(%d, %d) = %d, want %d", c.a, c.b, got, c.want)
        }
    }
}

func operation(a, b int) int {
    return a + b
}
Run Code Online (Sandbox Code Playgroud)


roo*_*ebo 9

自1.9以来情况发生了变化.

Helper()方法已添加到testing.T和testing.B.它旨在从测试帮助程序调用,例如assertSomething指示函数是一个帮助程序,我们对来自它的行号不感兴趣.

package main

import "testing"

func TestFoo(t *testing.T) {
    assertSomething(t, 2+2 == 4) // line 6
    assertSomething(t, 2+3 == 6) // line 7
}

func assertSomething(t *testing.T, expected bool) {
    if !expected {
        t.Helper()
        t.Error("Something's not right") // line 12
    }
}
Run Code Online (Sandbox Code Playgroud)

输出包含正确的行号:

=== RUN   TestFoo
--- FAIL: TestFoo (0.00s)
    main.go:7: Something's not right
FAIL
Run Code Online (Sandbox Code Playgroud)

您也可以在Go Playground上试试.