`test_assign_ids_with_cpk_for_two_models` の順序依存性を排除
Rails の自動保存関連テストで、PostgreSQL 環境下でのフレークが発生していました。TestDefaultAutosaveAssociationOnAHasManyAssociation#test_assign_ids_with_cpk_for_two_models が取得した book_ids 配列の順序に依存していたため、has_many :books が ORDER BY を付与しない場合にテストが失敗していました。この PR はその比較ロジックをソートして行うことで、順序に左右されない安定したテストへと改修しています。
背景
test_assign_ids_with_cpk_for_two_models は CPK(Composite Primary Keys)を使用した Order と Book の関連付けを検証するテストです。PostgreSQL では has_many :books のクエリに明示的な order: が無いため、結果セットのレコード順序はデータベース依存で不定となります。その不定性が原因で、ビルドキュー Buildkite の 129895 ビルドでテストが flake し、期待配列 [[550090038, 342015473], [550090038, 385957113]] と実際配列 [[550090038, 385957113], [550090038, 342015473]] が順序だけで不一致と判定されました。この現象はテストロジックが order‑dependent であることに起因しています。
技術的な変更
テストコードの assert_equal 行を assert_equal book_ids.sort, order.book_ids.sort に置換し、比較対象をソートした配列同士に変更しました。この変更は activerecord/test/cases/autosave_association_test.rb の該当箇所のみで、他のロジックやデータ構造に影響を与えません。以下に変更前後の差分を示します。
@@ -1005,7 +1005,7 @@ def test_assign_ids_with_cpk_for_two_models
order.save
order.reload
-
- assert_equal book_ids, order.book_ids
+ assert_equal book_ids.sort, order.book_ids.sort
assert_equal 2, order.books.length
assert_includes order.books, cpk_books(:cpk_great_author_first_book)
assert_includes order.books, cpk_books(:cpk_great_author_second_book)
このソート操作に加えて、テストは既に assert_includes と assert_equal 2, order.books.length で ID の集合と件数を検証しているため、ソートによるロジックの冗長化はありません。結果として、PostgreSQL の行順序が変動してもテストは安定して成功します。
設計判断
テストの比較ロジックを order‑independent に変更する方針は、データベース固有の実装詳細に依存しないテスト設計を意図しています。has_many 関連で明示的な order: が付与されていない限り、結果順序は保証できないため、テスト側で順序正規化を行うのが安全です。この判断は、既存テストが assert_includes 等で集合的検証を行っている点と整合し、追加のデータベースカラムやスコープを導入せずに問題を解消する最小侵害アプローチです。
まとめ
本 PR は test_assign_ids_with_cpk_for_two_models における order‑dependent 比較をソートに置き換えるだけで、PostgreSQL 環境でのフレークを根本的に排除しました。テストロジックの安定性が向上したことで、CI の信頼性が高まり、将来的なデータベース実装変更にも影響を受けにくい設計となります。