`ActiveSupport::TestCase.around` フックの導入

rails/rails

Active Support のテストケースに around コールバックが追加され、setupteardown の間を跨いだコンテキスト管理を1つのブロックで記述できるようになりました。これにより、Minitest ベースのプロジェクトでも他のフレームワークと同様の around フックを利用できます。

背景

Minitestには around フックが存在せず、これがプロジェクトの検討段階で代替テストハーネスへの移行を促す要因になることがありました。minitest/minitest#892 では around フックの組み込みが要望されてきましたが、Minitest 本体での実装は行わない方針が示されています。

サードパーティ製の minitest-hooks gem がこのギャップを埋めていましたが、Active Support はすでに ActiveSupport::Callbacks を持っており、Controller・Jobs・Mailers など他のコンポーネントと同じ仕組みで around フックを実装できる下地がありました。Active Support 側でこの機能を提供することで、外部 gem への依存なく、既存のコールバック体系と一貫した形で利用できます。

技術的な変更

ActiveSupport::Testing::SetupAndTeardown:test コールバックが追加され、around クラスメソッドが実装されました。

activesupport/lib/active_support/testing/setup_and_teardown.rbdefine_callbacks 呼び出しに :test が追加されています。

変更前:

klass.define_callbacks :setup, :teardown

変更後:

klass.define_callbacks :setup, :test, :teardown

ClassMethods モジュールに追加された around メソッドは、:test コールバックに :around フェーズとして登録します。また、初回呼び出し時にのみ AroundCallbackSupport モジュールを include する遅延インクルード方式を採用しています。

def around(*args, &block)
  set_callback(:test, :around, *args, &block)

  include AroundCallbackSupport unless self < AroundCallbackSupport
end

around ブロックはテストクラスのインスタンスとテストケース(ブロック)の2引数を受け取り、以下のように使用します。

class ClientTest < ActiveSupport::TestCase
  around do |test_case, block|
    Client.with(stubbed: true, &block)
  end
end

このコールバックは TestCase#setup コールバック群と TestCase#teardown コールバック群の間で実行されます。また、テストが失敗した場合でも block.call 以降のコードは実行されるため、リソースのクリーンアップを確実に行えます。

設計判断

AroundCallbackSupport の遅延インクルードが採用された点に注目できます。around を呼び出していないテストクラスには AroundCallbackSupport が混入されないため、#send メソッドのオーバーライドなどの副作用が around を使用するクラスにのみ限定されます。テストファイル activesupport/test/testing/around_callback_test.rb にも、around を呼び出していないクラスでは AroundCallbackSupport が祖先チェーンに含まれないことを確認するテストケースが明示的に追加されています。

test "does not override #send" do
  assert_not_includes self.class.ancestors, ActiveSupport::Testing::SetupAndTeardown::AroundCallbackSupport
end

また、既存の setupteardown に新しい独立したコールバックキー :test を追加する方式が選ばれています。これにより、setupteardown の実行順序は変わらず、around ブロックがその間のフェーズを包む構造が明確に表現されています。

まとめ

本PRは、Active Support が既に持つ Callbacks 基盤を活用して、最小限の変更で around フックを実現した変更です。遅延インクルードによる副作用の局所化と、既存コールバック体系との設計上の一貫性を両立しており、外部 gem なしに Minitest ベースの Rails テストで around フックが利用できるようになりました。

記事メタデータ

Generated by:
Claude Sonnet 4.6 for DiffDaily
LLM Trace:
8054267e

この記事はAIによって自動生成されています。内容の正確性については、必ずソースコードやPRを確認してください。

品質レビュー結果

Review Status:
承認済み
Review Count:
1回
Reviewed by:
Gemini 2.5 Pro for DiffDaily

Review Criteria:

記事構成 ✓ PASS

Title, Context, Technical Detailの存在と明確さ

リード文(総論)、背景・技術詳細・設計判断(各論)、まとめ(結論)という「総論→各論→結論」の構成が非常に明確です。必須要素はすべて満たされており、設計判断セクションも設けられていて内容が充実しています。

カスタムMarkdown構文 ✓ PASS

シンタックスハイライト・GitHubリンク記法の正確性

ファイル名付きシンタックスハイライト(```ruby:path/to/file.rb)や、Issue/PR番号のリンク記法([#123](URL))が正しく使用されています。

対象読者への適合性 ✓ PASS

エンジニア向けの適切な技術レベルと表現

Active SupportやMinitestに関する知識を前提としており、専門知識を持つエンジニアという対象読者に完全に適合しています。

パラグラフ・ライティング ✓ PASS

トピックセンテンス・1段落1トピック・段落長

各セクションが総論→各論の構造を持ち、各段落はトピックセンテンスで始まるなど、パラグラフ・ライティングの原則が徹底されています。非常に読みやすく、理解しやすい構成です。

Diff内容との照合 ✓ PASS

コードブロックとDiff内容の一致

記事内で引用されているコードブロックは、提供されたDiff情報とファイル名を含めて完全に一致しており、正確です。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

`ActiveSupport::Callbacks`、`define_callbacks`、`遅延インクルード`といった技術用語が正確かつ文脈に沿って適切に使用されています。

説明の技術的正確性 ✓ PASS

技術的主張の正確性と論理性

コールバックの実行順序、失敗時の挙動、遅延インクルードによる副作用の局所化など、技術的な説明はすべてPR情報やDiffのコードに基づいており、正確です。

事実の突合 ✓ PASS

PR情報による主張の裏付け(ハルシネーション検出)

記事内の主張(例:Minitestの方針、サードパーティgemの存在)は、すべてPRのDescriptionで裏付けが取れており、ハルシネーションは一切見られません。

数値・固有名詞の確認 ✓ PASS

PR番号・コミットID・バージョン等の正確性

PR番号(#50889)、Issue番号(minitest/minitest#892)、ファイルパスなどがすべて正確に記載されています。

タイトル・説明との一致 ✓ PASS

記事タイトル・説明とPR内容の一致

記事のタイトル「`ActiveSupport::TestCase.around` フックの導入」は、PRのタイトルと内容を正確に反映しています。

外部知識の正確性 ✓ PASS

PRに記載のない外部知識(LTS、サポート状況など)の不使用

記事の内容は提供されたPR情報に完全に準拠しており、バージョンサポート状況などの根拠のない外部知識の追加はありません。

時間表現の正確性 ✓ PASS

時間表現がPR情報と一致しているか

時間表現に関する記述はなく、時間軸の歪曲はありません。