mcpField
R
rails-testing

rails-testing

github.com/marckohlbruggeテスト・品質73052 回インストール20 週間前に更新
リポジトリ

rails-testing について

rails-testingは、Minitestとフィクスチャを用いたRailsアプリのテスト作成・レビュー向けスキルです。動作を重視したカバレッジ、決定性、適切なテスト層の選択を扱います。

主な機能

  1. 01Minitestとフィクスチャの規約
  2. 02動作を重視したテストカバレッジ
  3. 03テスト層の選び方
  4. 04非同期処理と外部境界のテスト
  5. 05認可とテナントのテストパターン

活用シーン

  1. 01Railsテストカバレッジのレビュー
  2. 02ユーザーワークフローの一連のテスト
  3. 03認可の回帰テスト追加

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/marckohlbrugge/37signals-skills --skill rails-testing

インストール後、Claude Code で/rails-testingを入力して読み込まれたか確認します。

詳細

Rails テスト

テスト作成やテストレビューのタスクで使用します。Campfire と Fizzy のテストスイートに基づくパターンです。

デフォルト

  • Minitest とフィクスチャを使用します。RSpec と FactoryBot は使用しません。
  • 実装の詳細ではなく、振る舞いをテストします。
  • テストは決定的かつ高速に保ちます。parallelize(workers: :number_of_processors) を使用します。
  • テストは機能と同じコミット/PR に含めます。先でも後でもありません。セキュリティ修正には必ず回帰テストを含めます。
  • テストしやすさのために、本番コードを複雑にすることは避けます(テストのために設計を損なわないでください)。

カバレッジの配分(37signals が実際に力を入れているところ)

  • 重点: モデルテスト(ドメインの不変条件、Concern)とコントローラー/インテグレーションテスト(リクエストの全サイクル、認証、フォーマット)。
  • 軽め: 重要なハッピーパスを対象とするシステムテストを少数(スモークテスト1つで、登録から利用までをカバーできます)。ジョブテストは実際のロジックがあるジョブのみを対象にします。
  • なし: ビューテスト、JS/Stimulus のユニットテスト、網羅的なチャネルテスト。UI の振る舞いはシステムテストで間接的にカバーします。
  • 同じ振る舞いのアサーションを複数の層で重複させないでください。

フィクスチャ

  • ID ではなくラベルで関連を表現します。相対的なタイムスタンプ(created_at: <%= 1.hour.ago %>)や、共有する計算済みの値(再利用する bcrypt ダイジェスト1つ)には ERB を使用します。
  • app/models の構成を test/models に反映します。app/models/card/closeable.rb ↔ test/models/card/closeable_test.rb、共有 Concern は test/models/concerns/ に配置します。
  • UUID の主キーはフィクスチャの順序に影響します。フィクスチャではラベルから生成した決定的な UUIDv7 を使い、.first/.last の順序を安定させ、実行時に作成されるレコードが常に新しくなるようにします。
  • リッチコンテンツのフィクスチャは、手書きのマークアップではなく本番コード(ActionText::Attachment.from_attachable(user).to_html)で作成します。

優れたプラクティス

  • ユーザーのワークフローにはシステム/インテグレーションテストを、ドメインの不変条件にはモデルテストを使用します。
  • 時間に依存するロジックには travel_to を使用します。
  • モック/スタブを使用するのは境界(外部 API、ネットワーク、時間、SecureRandom)に限ります。外部 HTTP には VCR を使用し、クラス名とテスト名からカセット名を自動生成して、照合時にはタイムスタンプを正規化します。
  • モデルテストから perform_enqueued_jobs(only: SpecificJob) と assert_enqueued_with を使って非同期の副作用をテストします。単純なジョブクラスをユニットテストする方法は避けます。
  • 関連する件数の変化は1つのアサーションで検証します。assert_difference({ -> { card.assignees.count } => -1, -> { Event.count } => +1 })。
  • コントローラーが複数のレスポンス形式を提供する場合は、両方をテストします。as: :turbo_stream(ストリームのターゲットを検証)と as: :json(ステータス、Location ヘッダー、本文)。
  • Turbo/ブロードキャストのアサーションは層ごとに使い分けます。モデルテストでは assert_turbo_stream_broadcasts、コントローラーテストでは assert_turbo_stream action:, target:、否定のケースでは assert_no_turbo_stream_broadcasts を使用します。
  • 認可テストでは、アクセスを許可するケースだけでなく、許可されない範囲も検証します。別テナント/別ロールからのアクセスが、許可されたアクセスの確認だけで終わらず、403/404 を返すことを検証します。
  • マルチテナントのテストスイートでは、セットアップ時に Current.account(振る舞いが実行者に依存する場合は Current.session も)を設定し、インテグレーション/システムテストでは default_url_options[:script_name] を設定します。認証ルート用に untenanted { } ヘルパーを用意します。ティアダウンで Current をクリアします。
  • ミドルウェアは Rack::MockRequest を使って単独でテストします。
  • システムテストでは、複数ユーザーのシナリオに using_session("Kevin") を使用し、リアルタイム機能を検証する前にケーブル接続を待ちます。認証には高速なセッション転送ヘルパーを使い、ログインの全フローは1つのスモークテストに限定します。
  • FTS テーブルのようにトランザクション外の副作用があるテストスイートでは、ヘルパー単位でオプトアウトします。self.use_transactional_tests = false を設定し、明示的にクリーンアップします。
  • 並列実行するテストスイートでは、スレッドプール、ActionCable.server.pubsub、Current などの共有グローバル状態をテストごとにリセットします。

注意すべき点

  • テストしやすさだけを目的に本番コードを複雑にすること。
  • アプリ内部のコードを過剰にモックすること。
  • 同じ振る舞いを複数の層で重複してテストすること。
  • 各テストで不要なセットアップを繰り返し、テストスイートを遅くすること(そのためにフィクスチャがあります)。
  • 1行だけのジョブクラスや単純な委譲をユニットテストすること。
  • 本番のレンダラー/ヘルパーなら自動的に同期を保てる箇所に、HTML 文字列を手書きすること。
  • travel_to を使わずに、時間に依存するアサーションを行うこと。

コメント