本記事でやること
Elasticsearchを使ったアプリケーションの統合テストにおいて、テストデータ(フィクスチャ)を簡単に管理するためのGoライブラリ「go-elasticsearch-testfixtures」を紹介します。
対象読者
- GoでElasticsearchを使ったアプリケーションを開発している方
- 統合テストでElasticsearchのテストデータ管理に課題を感じている方
- go-testfixturesを使ったことがある方
なぜ作ったのか
これまでいくつかのGo製API + Elasticsearchの構成でプロダクトを実装してきました。
毎回繰り返していたこと
- インデックス作成・削除のヘルパーメソッドを書く
- テストデータ投入処理を書く
- スタブデータの定義場所・型についてチームで議論する
本来やるべきこと
- どのようなテストをすべきか考える
- どのようなテストデータを用意すべきか考える
- 素早く実装する
定型的なセットアップコードではなく、テスト設計に時間をかけるべきです。
統一された方法でシンプルに管理したい。 そう思って作ったのが「go-elasticsearch-testfixtures」です。
go-testfixturesというアプローチ
Goには、RDB向けの優れたテストフィクスチャライブラリ「go-testfixtures」があります。
このライブラリは、YAMLファイルでテストデータを宣言的に管理し、Load()を呼ぶだけでデータベースをクリーンな状態にリセットしてくれます。
# testdata/fixtures/users.yml
- id: 1
name: Alice
email: alice@example.com
- id: 2
name: Bob
email: bob@example.com
fixtures.Load() // これだけでOK
このアプローチをElasticsearchにも適用したい。しかし、go-testfixturesのメンテナーは「非リレーショナルデータベースはこのパッケージのスコープ外」と明言しています。
"non-relational databases are out-of-the-scope of this package."
"If you're willing to work on that, that could be a different package since the code will differ a lot from testfixtures anyway."
そこで、go-testfixturesのアプローチにインスパイアされた別パッケージとして「go-elasticsearch-testfixtures」を作りました。
go-elasticsearch-testfixturesの設計
ディレクトリ構造 = インデックス構造
フィクスチャはディレクトリとファイルで管理します。
testdata/fixtures/
├── users/
│ ├── _mapping.json # インデックスのマッピング定義
│ ├── _settings.json # インデックスの設定(任意)
│ └── documents.yml # テストドキュメント
└── products/
├── _mapping.json
└── documents.yml
- 各サブディレクトリがElasticsearchのインデックスに対応
-
_mapping.jsonでマッピングを定義(ES Mappings APIと同じ形式) -
_settings.jsonで設定を定義(任意) -
*.ymlファイルにテストドキュメントを記述
ファイル形式
_mapping.json
{
"properties": {
"name": { "type": "text" },
"email": { "type": "keyword" },
"age": { "type": "integer" }
}
}
documents.yml
- _id: "1"
name: "Alice"
email: "alice@example.com"
age: 30
- _id: "2"
name: "Bob"
email: "bob@example.com"
age: 25
_idフィールドは特別扱いされ、ElasticsearchのドキュメントIDとして使用されます。省略すると自動生成されます。
削除→再作成でテスト間の干渉を防止
Load()を呼ぶと、以下の処理が実行されます。
- 既存のインデックスを削除
- マッピング・設定を適用してインデックスを作成
- ドキュメントを一括挿入
- インデックスをリフレッシュ(即座に検索可能に)
毎回クリーンな状態からスタートするので、テスト間の干渉を確実に防げます。
使い方
インストール
go get github.com/kurakura967/go-elasticsearch-testfixtures
基本的な使い方
var fixtures *testfixtures.Loader
func TestMain(m *testing.M) {
client, _ := elasticsearch.NewClient(elasticsearch.Config{
Addresses: []string{"http://localhost:9200"},
})
fixtures, _ = testfixtures.New(
client,
testfixtures.Directory("testdata/fixtures"),
)
os.Exit(m.Run())
}
func TestSearchUsers(t *testing.T) {
fixtures.Load()
t.Cleanup(func() { fixtures.Clean() })
// テスト本体
}
テスト例
func TestSearchUsers(t *testing.T) {
if err := fixtures.Load(); err != nil {
t.Fatal(err)
}
t.Cleanup(func() { fixtures.Clean() })
// age >= 30 のユーザーを検索
query := `{
"query": {
"range": { "age": { "gte": 30 } }
}
}`
res, err := client.Search(
client.Search.WithIndex("users"),
client.Search.WithBody(strings.NewReader(query)),
)
if err != nil {
t.Fatal(err)
}
defer res.Body.Close()
// 結果を検証...
}
今後の展望
現在の実装はシンプルですが、以下の機能追加を検討しています。
- インデックスプレフィックス対応: テストごとにユニークなプレフィックスを付けることで、並列テスト実行をサポート
- テンプレート機能: go-testfixturesのように、YAMLファイル内でGoテンプレートを使用できるように
- 複数のフィクスチャセット: テストシナリオに応じて異なるデータセットを切り替え
まとめ
テストコードは、ビジネスロジックの検証に集中すべきです。セットアップの定型作業はライブラリに任せましょう。
「go-elasticsearch-testfixtures」は、Elasticsearchの統合テストにおけるフィクスチャ管理をシンプルにするためのライブラリです。
OSSとして公開しているので、ぜひ使ってみてください。フィードバックやContributionも歓迎です!
GitHub: https://github.com/kurakura967/go-elasticsearch-testfixtures