Issue
I’m writing some test for a Go module. A lot of it is checking that functions return the correct values. This is a simple example for what I’m currently doing:
package foo
import (
"reflect"
"testing"
)
func Foo() int {
return 3
}
func TestFoo(t *testing.T) {
expected := 4
actual := Foo()
if !reflect.DeepEqual(actual, expected) {
t.Errorf("actual=%v, expected=%v", actual, expected)
}
}
A single test might contain a many such equality checks. Duplicating these 6 lines for each check makes the tests hard to read and error-prone to write (from what I’ve experienced the past few days). So I thought I’d make an assertEquals()
function that wraps the whole logic similar to what other testing frameworks provide (e.g. in JUnit’s org.junit.Assert
):
func TestFoo(t *testing.T) {
assertEqual(t, 4, Foo())
}
func assertEqual(t *testing.T, actual interface{}, expected interface{}) {
if !reflect.DeepEqual(actual, expected) {
t.Errorf("Assertion failed: %v != %v", actual, expected)
}
}
The problem now is that Errorf()
will obviously not show the line where assertEqual()
is called but the call to Errorf()
inside of assertEqual
:
=== RUN TestFoo
foo_test.go:28: Assertion failed: 4 != 3
--- FAIL: TestFoo (0.00s)
Is there a way to fix that, e.g. by showing the whole stack trace instead of only the location of the call to Errorf()
?
Or is there a better way to avoid repeating those lines of code to check the return value of a function?
Solution
As mentioned in comments, you can use t.Helper()
:
Helper marks the calling function as a test helper function. When printing file and line information, that function will be skipped. Helper may be called simultaneously from multiple goroutines.
So your helper function becomes:
func assertEqual(t *testing.T, actual interface{}, expected interface{}) {
t.Helper()
if !reflect.DeepEqual(actual, expected) {
t.Errorf("Assertion failed: %v != %v", actual, expected)
}
}
Output:
=== RUN TestFoo
prog.go:13: Assertion failed: 4 != 3
--- FAIL: TestFoo (0.00s)
FAIL
where prog.go:13
in this playground is the line in the main test target that calls assertEqual
instead of t.Errorf
within it.
This will only change the file line in the testing output. If you actually want the full stack trace, you can use runtime.Caller
as mentioned in these two threads.
Answered By – blackgreen
Answer Checked By – Willingham (GoLangFix Volunteer)