Go言語のテストでmockを使う基本とinterface活用のコツ
生徒
「Go言語でデータベースを使う関数をテストしたいのですが、実際のデータベースを使わずに確認する方法はありますか?」
先生
「その場合、mockを使う方法があります。mockは本物の代わりに使うテスト用の置き換えオブジェクトです。」
生徒
「mockを作るのは難しいですか?」
先生
「Goではinterfaceを活用すると簡単に作れます。本物の機能と同じ形のinterfaceを定義して、それを実装するmockを作るのです。」
1. interfaceを使ったmockの基本
interfaceはGo言語で型の振る舞いを定義する仕組みです。関数がinterfaceを受け取るように設計すると、本物の処理とmockを切り替えてテストできます。
例えば、データベースに値を保存する処理を考えてみます。
type Database interface {
Save(key string, value string) error
}
func StoreData(db Database, key, value string) error {
return db.Save(key, value)
}
ここではDatabaseというinterfaceを定義し、StoreData関数はこのinterfaceを受け取る設計になっています。
2. mockの作り方
テスト用のmockは、interfaceを実装するだけで作れます。処理の中で呼び出されたことを記録したり、任意のエラーを返したりできます。
type MockDatabase struct {
Saved map[string]string
}
func (m *MockDatabase) Save(key string, value string) error {
if m.Saved == nil {
m.Saved = make(map[string]string)
}
m.Saved[key] = value
return nil
}
このmockは保存処理を記録するだけで、実際のデータベースには触りません。
3. mockを使ったテスト例
作成したmockを使って関数をテストできます。本物のデータベースを用意する必要がないので、テストが簡単かつ高速に実行できます。
import "testing"
func TestStoreData(t *testing.T) {
mockDB := &MockDatabase{}
key, value := "user1", "Alice"
err := StoreData(mockDB, key, value)
if err != nil {
t.Errorf("StoreData returned error: %v", err)
}
if mockDB.Saved[key] != value {
t.Errorf("Expected %s, got %s", value, mockDB.Saved[key])
}
}
mockを使うことで、関数の動作とmockへのデータ保存が正しく行われているかを簡単に確認できます。
4. mock活用のコツ
- 関数がinterface型を受け取るように設計する。
- mockでは本物の処理を行わず、必要な情報だけを記録する。
- 任意のエラーや特殊な動作を返すようにして、異常系もテストできる。
- 複雑な依存関係を持つ処理でも、mockを使うことで単体テストが容易になる。
このようにmockとinterfaceを組み合わせることで、Go言語でのテストは効率的に行えます。特に外部サービスやデータベースに依存する処理のテストでは必須の技術です。
5. 初心者へのアドバイス
最初は小さな関数でmockを試すのが良いです。interfaceの使い方、mockの実装、テスト関数での確認手順を順に理解すると、より大きなアプリケーションのテストにも応用できます。mockを使うことで、実際の環境を準備せずにテストができるので、開発スピードの向上にもつながります。