testifylint は testify ライブラリの使い方をチェックし、より適切なアサーション関数の使用を促すツールです。
解決する問題
testify は Go で最も広く使われるテストライブラリですが、API が豊富なため不適切な関数の選択が起きやすくなります。失敗メッセージの可読性が低下したり、テストが意図通りに動作しない原因になります。
1 2 3 4 5 6 7 8 9
| func TestUser(t *testing.T) { user, err := GetUser("123")
assert.Equal(t, nil, err) assert.Equal(t, true, user != nil) assert.True(t, user.Name == "Alice") assert.Equal(t, 0, len(user.Tags)) }
|
1 2 3 4 5 6 7 8 9
| func TestUser(t *testing.T) { user, err := GetUser("123")
assert.NoError(t, err) assert.NotNil(t, user) assert.Equal(t, "Alice", user.Name) assert.Empty(t, user.Tags) }
|
設定
公式ドキュメント
1 2 3 4 5 6 7 8 9 10 11
| version: "2"
linters: enable: - testifylint settings: testifylint: enable-all: true disable: - suite-thelper
|
オプション
| オプション |
型 |
デフォルト |
説明 |
enable-all |
bool |
false |
すべてのチェッカーを有効化する |
disable-all |
bool |
false |
すべてのチェッカーを無効化する |
enable |
[]string |
[] |
有効化するチェッカーのリスト |
disable |
[]string |
[suite-thelper] |
無効化するチェッカーのリスト |
主要なチェッカー
アサーション選択
| チェッカー |
Bad |
Good |
bool-compare |
assert.Equal(t, true, v) |
assert.True(t, v) |
compares |
assert.True(t, a == b) |
assert.Equal(t, a, b) |
empty |
assert.Len(t, arr, 0) |
assert.Empty(t, arr) |
len |
assert.Equal(t, 3, len(arr)) |
assert.Len(t, arr, 3) |
nil-compare |
assert.Equal(t, nil, v) |
assert.Nil(t, v) |
negative-positive |
assert.True(t, v > 0) |
assert.Positive(t, v) |
contains |
assert.True(t, strings.Contains(s, "x")) |
assert.Contains(t, s, "x") |
regexp |
assert.True(t, regexp.MatchString(p, s)) |
assert.Regexp(t, p, s) |
エラー処理
| チェッカー |
Bad |
Good |
error-nil |
assert.Nil(t, err) |
assert.NoError(t, err) |
error-is-as |
assert.True(t, errors.Is(err, target)) |
assert.ErrorIs(t, err, target) |
require-error |
assert.NoError(t, err) の後に続行 |
require.NoError(t, err) |
テスト品質
| チェッカー |
検出内容 |
expected-actual |
assert.Equal の引数順序(expected, actual)の誤り |
float-compare |
浮動小数点数の直接比較(assert.InDelta を使うべき) |
useless-assert |
常に成功するアサーション |
go-require |
goroutine 内での require の使用(テストを安全に中断できない) |
formatter |
フォーマット文字列の不正使用 |
サンプル
検出例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| func TestOrder(t *testing.T) { order, err := CreateOrder(item)
assert.Nil(t, err)
assert.Equal(t, order.Total, 100)
assert.Equal(t, 3.14, order.Tax)
assert.NoError(t, err) assert.Equal(t, "pending", order.Status) }
|
修正例
1 2 3 4 5 6 7 8
| func TestOrder(t *testing.T) { order, err := CreateOrder(item)
require.NoError(t, err) assert.Equal(t, 100, order.Total) assert.InDelta(t, 3.14, order.Tax, 0.001) assert.Equal(t, "pending", order.Status) }
|
注意点
require-error チェッカーは特に重要。assert.NoError は失敗してもテストを続行するため、後続のアサーションで nil ポインタパニックが発生する可能性がある
expected-actual チェッカーはデフォルトで ^(exp(ected)?|want(ed)?) にマッチする変数を expected とみなす
- 多くのチェッカーが autofix に対応しており、
golangci-lint run --fix で自動修正できる
参考リンク