デフォルト順序テストから順序未保証のベースラインアサーションを除去
Rails Nightly ビルド #4408 で HasManyAssociationsTest#test_default_order が失敗し、期待した [1, 2] と実際の [2, 1] が食い違う事象が報告されました。原因は comments.pluck(:id) が ORDER BY を付与せずに実行され、PostgreSQL では結果順序が保証されないためです。今回の PR は同様のベースラインアサーションを HasManyAssociationsTest と RelationTest の test_default_order から削除し、テストの安定性を向上させます。
背景
test_default_order は default_order 機能の挙動を確認するためのテストですが、当初は順序付けられていない関連データに対して [1, 2] という固定期待値をチェックしていました。PostgreSQL では SELECT "comments"."id" FROM "comments" WHERE "comments"."post_id" = $1 のように ORDER BY が無いため、行が返る順序は実行毎に変動し、結果としてテストがフレーキーになることが判明しました。HasManyAssociationsTest#test_default_order と RelationTest#test_default_order の両方で同様のベースラインが存在し、どちらも nightly ビルドで失敗していました。
この問題はテストが default_order の実装ではなく、単に結果がソートされていないことを前提にしていた点に起因します。結果が不定であることはデータベース固有の挙動であり、テストコード側で明示的に順序を保証しない限り安定しません。したがって、ベースラインアサーションはテストの目的から外れ、削除する方が適切と判断されました。
技術的な変更
activerecord/test/cases/associations/has_many_associations_test.rb の test_default_order から、順序未保証のベースラインを表す 4 行が削除されました。削除前は以下のようになっていました。
comments = post.comments
assert_equal [1, 2], comments.pluck(:id)
assert_equal 1, comments.first.id
削除後は order(:body) を用いた部分だけが残り、期待値は明示的に順序付けられた結果に対して検証されます。
comments = post.comments.order(:body)
assert_equal [2, 1], comments.pluck(:id)
assert_equal 2, comments.first.id
同様に activerecord/test/cases/relations_test.rb の test_default_order でも、未ソートの comments = posts(:welcome).comments とそれに対する 2 つの assert_equal が除去され、代わりに default_order(:body) を適用した結果だけがテスト対象となります。
- comments = posts(:welcome).comments
- assert_equal [1, 2], comments.pluck(:id)
- assert_equal 1, comments.first.id
-
- comments = comments.default_order(:body)
+ comments = posts(:welcome).comments.default_order(:body)
assert_equal [2, 1], comments.pluck(:id)
assert_equal 2, comments.first.id
この変更はテストコードの削除に留まり、実装側のロジックや API は一切変更されていません。結果として、default_order の正しい動作は引き続き検証されますが、順序未保証の余計なアサーションが無くなることでフレーキーが解消されます。
設計判断
ベースラインアサーションを sort して deterministic にする案も検討されましたが、ソート後の期待値は既に別テストでカバーされており、冗長になると判断されました。つまり、重複したテスト を増やすよりも、不安定なアサーションを削除 してテストスイートの信頼性を保つ選択が取られました。
今回の削除は default_order 機能の本質的なテストを損なわず、むしろ目的外の順序に依存したチェックを排除することで設計の明快さを高めています。フレーキーが減少すれば CI の安定性が向上し、開発者は本来の機能検証に集中できます。
まとめ
test_default_order から順序未保証のベースラインアサーションを除去したことで、テストのフレーキーが解消され、Rails の default_order 機能に関するテストがより堅牢になりました。実装変更はなく、テストコードの整理だけで信頼性を向上させた典型的なリファクタリングです。