Minitest 6対応:Railsバージョン別の依存管理戦略
Minitest 6がminitest/mockを別Gem(minitest-mock)に分離したことで生じたテスト破損に対し、Rails 7.0〜8.1の各バージョン特性に応じた段階的な対応が行われました。
背景
Minitest 6へのメジャーアップグレードで、従来コアに含まれていたminitest/mockが独立Gem(minitest-mock)として切り出されました。これにより、テストファイルでrequire "minitest/mock"を呼び出しているプロジェクトはMinitest 6環境下でロードエラーが発生するようになりました。
propshaftのテストスイートもこの影響を受けており、Rails 7.0〜8.1を対象とした複数のGemfileをそれぞれ適切に対処する必要がありました。ただし、各Railsバージョンがminiteを自身のgemspecで制約しているかどうかが異なるため、一律の対応は取れない状況でした。参照コミットrails/rails@6ea6070が示すように、Rails 7.2はMinitestをバージョン5に固定する対応を既にgem側で行っています。
この非均一な状況が、Railsバージョンごとに異なる対応方針を採用する設計判断につながっています。
技術的な変更
各Railsバージョン向けのGemfileは、そのバージョンの制約状況に応じて3つのパターンで対応が分かれています。
Rails 7.0・7.1(gemfiles/Gemfile.rails-7.0・gemfiles/Gemfile.rails-7.1)は、Minitest 6への移行を回避する方針です。これらのバージョンはgem側でminiteを制約していないため、明示的にminitest < 6のバージョン制約を追加しています。
gem "minitest", "< 6"
Rails 7.2(gemfiles/Gemfile.rails-7.2)は、Rails本体側で既にminitest < 6が固定されているため、propshaftの側からバージョン制約を追加する必要はありません。しかしrequire "minitest/mock"はそのまま機能させる必要があるため、minitest-mock(スタンドアロンのバックポート互換Gem)を追加しています。
gem "minitest-mock"
Rails 8.0・8.1およびルートGemfileは、Minitest 6をそのまま採用したうえでminitest-mockを追加する構成です。新規追加されたgemfiles/Gemfile.rails-8.1も同様のパターンに従っています。
source "https://rubygems.org"
gemspec path: ".."
gem "rails", "~> 8.1"
gem "minitest-mock"
gem "rake"
gem "debug"
CIマトリクス(.github/workflows/ci.yml)にはRails 8.1が追加され、Ruby 3.1との組み合わせは除外設定が加えられています。
- "8.1"
- ruby-version: "3.1"
rails-version: "8.1"
設計判断
バージョン別に対応を分岐させる方針が採用されました。単純にminitest < 6で全環境を固定するアプローチもありましたが、このPRではRailsバージョンの成熟度・サポート状況に応じた細かい対応が選ばれています。
Rails 7.0・7.1は自前でminiteを制約しないため、propshaft側でピン止めすることで問題を回避します。Rails 7.2はRails本体がピン止め済みのため、propshaft側ではminitest-mockの追加だけで事足ります。Rails 8.0・8.1は新しいバージョンであることから、Minitest 6へのフル移行とminitest-mockの追加という積極的な対応を取っています。この三段階の処理は、「既存バージョンへの影響を最小化しつつ、新バージョンでは最新のエコシステムに追従する」という方針を体現しています。
まとめ
この変更は、単一のソリューションを押し付けるのではなく、各Railsバージョンの依存関係の実態を精査した上で最適な対応を選択した事例です。minitest-mockというスタンドアロンGemが互換性のブリッジとして機能することで、Rails 7.2〜8.1のすべての環境でテストコードの変更なしにMinitest 6対応が実現されています。