かまたま日記3

プログラミングメイン、たまに日常

Goでtesting.T#Helperを使う

Goのテストでヘルパーメソッドを作って共通のアサーションを定義することがあるかと思います。

package test

import "testing"

func Add(x, y int) int {
    return x + y
}

func TestAdd(t *testing.T) {
    AssertEquals(t, 2, Add(1, 1))
    AssertEquals(t, 3, Add(1, 2))
    AssertEquals(t, 4, Add(1, 3))
}

func AssertEquals(t *testing.T, expected, actual int) {
    if expected != actual {
        t.Errorf("Unexpected int\nexpected:%d, actual:%d", expected, actual)
    }
}

ここで言う AssertEquals が共通のアサーションですね。 これをこんな感じで、わざと失敗させてると以下のような出力になります。

func TestAdd(t *testing.T) {
    AssertEquals(t, 1, Add(1, 1))
    AssertEquals(t, 2, Add(1, 2))
    AssertEquals(t, 3, Add(1, 3))
}
=== RUN   TestAdd
    TestAdd: add_test.go:17: Unexpected int
        expected:1, actual:2
    TestAdd: add_test.go:17: Unexpected int
        expected:2, actual:3
    TestAdd: add_test.go:17: Unexpected int
        expected:3, actual:4
--- FAIL: TestAdd (0.00s)
FAIL

出力される行番号が全部ヘルパーメソッドの位置になってて実際のテストのどこで失敗したかが分かりづらいですね。 *1

こういうときは t.Helper() を呼ぶとそのヘルパーメソッドがcallerのスタックから除外されます。

AssertEquals関数を以下のように変更して実行します

func AssertEquals(t *testing.T, expected, actual int) {
    t.Helper()
    if expected != actual {
        t.Errorf("Unexpected int\nexpected:%d, actual:%d", expected, actual)
    }
}
=== RUN   TestAdd
    TestAdd: add_test.go:10: Unexpected int
        expected:1, actual:2
    TestAdd: add_test.go:11: Unexpected int
        expected:2, actual:3
    TestAdd: add_test.go:12: Unexpected int
        expected:3, actual:4
--- FAIL: TestAdd (0.00s)
FAIL

実際のアサーションを実行しているテストケースの行番号になりました。

まとめ

テストのヘルパーメソッドでは t.Helper() を呼び出すべし

*1:本来はこういうテストは一つのケースにまとめないでケースを分けるなどをした方が良いと思います