はじめに
こんにちは!フリーランスエンジニアのこたろうです。
今回は、Goで直接関数呼び出しを含むコードをテスト可能にする最もシンプルな方法を紹介します。
テスト難しい直接関数呼び出し
次のようなコードがあるとします:
func ProcessUser(userID string) (*ProcessedData, error) {
// 直接関数を呼び出している - テスト時に置き換えられない
user, err := GetUserFromDB(userID)
if err != nil {
return nil, err
}
// 結果の作成
return &ProcessedData{
UserName: user.Name,
ProcessedAt: time.Now(),
}, nil
}
// 実際のデータベースアクセスを行う関数
func GetUserFromDB(id string) (*User, error) {
// 実際のDB処理(テスト時には実行したくない)
db, err := sql.Open("mysql", "user:password@/dbname")
if err != nil {
return nil, err
}
defer db.Close()
// データベース処理...
return &User{ID: id, Name: "John"}, nil
}
シンプルな解決策:関数変数化
わずか2行の変更で、テスト可能なコードに変えられます:
// 通常の関数定義をそのまま残す
func GetUserFromDB(id string) (*User, error) {
// 実際のDB処理
db, err := sql.Open("mysql", "user:password@/dbname")
if err != nil {
return nil, err
}
defer db.Close()
// データベース処理...
return &User{ID: id, Name: "John"}, nil
}
// 変数に関数を代入
var GetUserFromDBFunc = GetUserFromDB
// ProcessUser関数も少し修正
func ProcessUser(userID string) (*ProcessedData, error) {
// 直接呼び出す代わりに変数経由で呼び出す
user, err := GetUserFromDBFunc(userID) // ここだけ変更
if err != nil {
return nil, err
}
return &ProcessedData{
UserName: user.Name,
ProcessedAt: time.Now(),
}, nil
}
モックを使ったテスト
この変更により、テスト時に関数をモックに置き換えることが可能になります:
func TestProcessUser(t *testing.T) {
// 元の関数を保存
originalFunc := GetUserFromDBFunc
// テスト終了時に元に戻す
defer func() {
GetUserFromDBFunc = originalFunc
}()
// モック関数を設定
GetUserFromDBFunc = func(id string) (*User, error) {
// テスト用のモック実装
return &User{ID: id, Name: "Test User"}, nil
}
// テスト実行
result, err := ProcessUser("123")
// 検証
assert.NoError(t, err)
assert.Equal(t, "Test User", result.UserName)
}
エラーケースのテスト
エラーパターンも同様に簡単にテストできます:
func TestProcessUser_Error(t *testing.T) {
// 元の関数を保存して後で復元
originalFunc := GetUserFromDBFunc
defer func() { GetUserFromDBFunc = originalFunc }()
// エラーを返すモック関数
GetUserFromDBFunc = func(id string) (*User, error) {
return nil, errors.New("database error")
}
// テスト実行
result, err := ProcessUser("123")
// 検証
assert.Error(t, err)
assert.Nil(t, result)
}
この方法のメリット
- コード変更が最小限(たった2行)
- シンプルで理解しやすい
- 既存コードへの影響が少ない
- 特別なライブラリやフレームワークが不要
まとめ
Goで関数を変数化する方法は、テスタビリティを向上させる最もシンプルな手法の一つです。既存のコードに対しても最小限の変更で導入できるため、レガシーコードのリファクタリングや、急いでテストを書く必要がある場合に非常に有効です。