この記事は、tacoms Advent Calendar 2024の5日目です!
他メンバーのAdvent Calendarはこちらからご覧ください!👇
背景
mock使っていますか?
単体テストにおいてmockを活用するのは一般的ですが、テストケースごとにmock生成しDIするのは冗長になりがちで、可読性も良くありません。
例えば、以下のような具合です。(弊社ではmockeryというライブラリを使っています。)
func TestCreateTask(t *testing.T) {
// userのmock初期化
userMock := mock.NewUser(t)
userMock.Expect().GetUser(ctx, "1").Return(&User{}, nil)
// userGroupのmock初期化
userGroupMock := mock.NewUserGroup(t)
userGroupMock.Expect().ListUserGroups(ctx, []string{"2", "3"}).Return([]*UserGroup{}, nil)
// taskのmock初期化
taskGroupMock := mock.NewUserGroup(t)
taskGroupMock.Expect().Create(ctx, &Task{}).Return(nil)
// mockを注入
server := &Server{
User: userMock,
UserGroup: userGroupMock,
Task: taskGroupMock,
}
err := server.CreateTask(ctx, "some task")
assert.NoError(t, err)
}
このように、生成する対象のmockが多ければ多いほど初期化がつらくなってきます。
また、生成したmockはテスト対象の構造体にDIしなければならないため、そのコード自体も冗長化しがちです。
解決方法
mock生成をまとめる関数の導入
以下のように、mockの生成からDIを一箇所でまとめてやってみます。
これによってテストケース毎にmockを生成してDIするコードを書く手間が省けます。
また、新しいmockが必要になった時は、誰かがそれを追加しさえすれば、他の人は利用するだけで済みます。
type mock struct {
user *mock.MockUser
userGroup *mock.MockUserGroup
task *mock.MockTask
// and so on
}
func newMock(t *testing.T) (*server, *mock) {
m := &mock{
user: persistencemock.NewMockUser(t),
userGroup: persistencemock.NewMockUserGroup(t),
task: persistencemock.NewMockTask(t),
// and so on
}
s := &server{
User: m.user,
UserGroup: m.userGroup,
Task: m.task,
// and so on
}
return s, m
}
実際のテストでの利用
使う側はnewMock関数を呼び出すだけです。
本記事の一番上で例に出した冗長なコードよりもスッキリしたのではないでしょうか?
func TestCreateTask(t *testing.T) {
// mockをまとめて初期化しDI
server, mock := newMock(t)
mock.user.Expect().GetUser(ctx, "1").Return(&User{}, nil)
mock.userGroup.Expect().ListUserGroups(ctx, []string{"2", "3"}).Return([]*UserGroup{}, nil)
mock.task.Expect().Create(ctx, &Task{}).Return(nil)
err := server.CreateTask(ctx, "some task")
assert.NoError(t, err)
}
まとめ
今回のアプローチにより、以下のメリットが得られました。
- テストコードの可読性とメンテナンス性が向上した
- mockの追加や変更が容易になった
- テストロジックに集中できる環境が整備された
- 書きっぷりの統一された
今回の例は、導入コストが低く、すぐに実践できる方法を紹介しました。しかし、他にもDI系ライブラリや、テスト用フレームワークを活用することでさらに効率化することも可能かと思います。
プロジェクトの規模や要件に応じて、最適なアプローチを選ぶことが重要です。
PR
現在株式会社 tacoms では全ポジションで絶賛採用募集中です!
是非気軽にカジュアル面談からお話ししましょう 👏