How to fix line numbers in Go test output?

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
}

Tags:

Testing

Go