如何在Go测试输出中确定行号?
Let's consider this simple testing code.
(Note: assertSomething
is super simple here, but normally I'd write a more specialised helper for the task at hand that would look at multiple things and could report more than one type of error.)
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
}
}
When I run go test
, I get the following:
--- FAIL: TestFoo (0.00s)
hello.go:12: Something's not right
FAIL
exit status 1
FAIL kos/hello 0.008s
I have two questions:
1) The error points to line 12 - why? How does t.Error
find out which line it was called from?
2) In the helper, I'd like to specify that t.Error
should look stack level higher to determine the line number to print, so that I would get a message like this:
--- FAIL: TestFoo (0.00s)
hello.go:7: Something's not right
Python allows me to do this, for instance, in warnings.warn("message", stacklevel=2)
- how would I implement the equivalent here?
让我们考虑一下这个简单的测试代码。 p>
(注意: 当我运行 我有两个问题: p>
1)错误指向第12行-为什么? 2)在帮助器中,我想指定该 例如,Python允许我在 assertSomething code>在这里非常简单,但是通常我会为手头的任务编写一个更专业的助手,该助手会查看多种情况并报告多种错误。) em>
包hello
import“ testing”
func TestFoo(t * testing.T){
assertSomething(t,2 + 2 == 4)// 第6行
assertSomething(t,2 + 3 == 6)//第7行
}
func assertSomething(t * testing.T,预期的布尔值){
如果!expected {
t.Error( “某事不正确”)//第12行
}
}
code> pre>
go test code>时,我得到以下信息 : p>
---失败:TestFoo(0.00s)
hello.go:12:某些地方不正确
FAIL
exit状态1
FAIL kos / hello 0.008s \ n code> pre>
t.Error code>如何找出从哪一行调用的? p>
t。 错误 code>应该看起来在堆栈级别更高,以确定要打印的行号,这样我会收到如下消息: p>
--- FAIL:TestFoo(0.00 s)
hello.go:7:有些不对
code> pre>
warnings.warn(” message“,stacklevel = 2) code>
- 我在这里实现等效功能吗? p>
div>
Things have changed since go 1.9.
Helper()
method has been added to testing.T
and testing.B
. It's intended to be invoked from testing helpers such as assertSomething
to indicate the function is a helper and we're not interested in line numbers coming from it.
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
}
}
The output contains correct line numbers:
=== RUN TestFoo
--- FAIL: TestFoo (0.00s)
main.go:7: Something's not right
FAIL
You can also try it on Go Playground.
You can do what you're asking, and you can find out how t.Error
works by looking at the source code. The function decorate
is what you're looking for I think.
But, in the case where you have significant amounts of checking code, and for some reason it's getting duplicated in your test, it's better to extract that as a function that returns an error than passing in a testing.T and making it an "assertion". Indeed, writing assertion functions is explicitly discouraged in the language 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
}
But here's what I think idiomatic testing code would look like. It's table-driven, and the cases include inputs and expected output, leading to really clear error messages when the tests fail.
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
}