mcpField
R
rspec

rspec

github.com/el-feoテスト・品質1238 回インストール14 週間前に更新
リポジトリ

rspec について

Ruby と Rails のプロジェクトでテストを書く開発者向けの RSpec ガイドスキルです。複数の spec 種別、テストダブル、Factory Bot、テスト性能の指針を扱います。

主な機能

  1. 01モデル、リクエスト、システム spec の指針
  2. 02Factory Bot によるテストデータ戦略
  3. 03マッチャー、モック、スタブの解説
  4. 04TDD とテスト階層化の指針
  5. 05Rails 設定と性能改善の実践

活用シーン

  1. 01Rails モデルのビジネスロジックをテスト
  2. 02API リクエスト、認証、レスポンスをテスト
  3. 03ブラウザーでユーザーワークフローを検証
  4. 04テストスイートの遅いテストを削減

インストール

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

$npx skills add https://github.com/el-feo/ai-context --skill rspec

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

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

references/
best_practices.md
configuration.md
core_concepts.md
factory_bot.md
matchers.md
mocking.md
rails_testing.md

詳細

RSpec テストスキル

Ruby および Rails アプリケーションで包括的なテストを記述するための、RSpec に関する専門的なガイダンスです。このスキルでは、すぐに実践できるテスト戦略と、複雑なシナリオに対応する詳細なリファレンスを提供します。

クイックスタート

RSpec の基本構造
# spec/models/user_spec.rb
RSpec.describe User, type: :model do
  describe '#full_name' do
    it 'returns the first and last name' do
      user = User.new(first_name: 'John', last_name: 'Doe')
      expect(user.full_name).to eq('John Doe')
    end
  end
end

主な概念:

  • describe:関連するテスト(クラス、メソッド)をグループ化します
  • context:特定のシナリオを記述します
  • it:個々のテスト例です
  • expect:マッチャーを使ってアサーションを行います
テストの実行
# Run all specs
bundle exec rspec

# Run specific file
bundle exec rspec spec/models/user_spec.rb

# Run specific line
bundle exec rspec spec/models/user_spec.rb:12

# Run with documentation format
bundle exec rspec --format documentation

# Run only failures from last run
bundle exec rspec --only-failures

基本的なテストパターン

1. モデルスペック

ビジネスロジック、バリデーション、関連付け、メソッドをテストします。

RSpec.describe Article, type: :model do
  # Test validations
  describe 'validations' do
    it { should validate_presence_of(:title) }
    it { should validate_length_of(:title).is_at_most(100) }
  end

  # Test associations
  describe 'associations' do
    it { should belong_to(:author) }
    it { should have_many(:comments) }
  end

  # Test instance methods
  describe '#published?' do
    context 'when publish_date is in the past' do
      it 'returns true' do
        article = Article.new(publish_date: 1.day.ago)
        expect(article.published?).to be true
      end
    end

    context 'when publish_date is in the future' do
      it 'returns false' do
        article = Article.new(publish_date: 1.day.from_now)
        expect(article.published?).to be false
      end
    end
  end

  # Test scopes
  describe '.recent' do
    it 'returns articles from the last 30 days' do
      old = create(:article, created_at: 31.days.ago)
      recent = create(:article, created_at: 1.day.ago)

      expect(Article.recent).to include(recent)
      expect(Article.recent).not_to include(old)
    end
  end
end
2. リクエストスペック

スタック全体を通した HTTP リクエストとレスポンスをテストします。

RSpec.describe 'Articles API', type: :request do
  describe 'GET /articles' do
    it 'returns all articles' do
      create_list(:article, 3)

      get '/articles'

      expect(response).to have_http_status(:success)
      expect(JSON.parse(response.body).size).to eq(3)
    end
  end

  describe 'POST /articles' do
    context 'with valid params' do
      it 'creates a new article' do
        article_params = { article: { title: 'New Article', body: 'Content' } }

        expect {
          post '/articles', params: article_params
        }.to change(Article, :count).by(1)

        expect(response).to have_http_status(:created)
      end
    end

    context 'with invalid params' do
      it 'returns errors' do
        invalid_params = { article: { title: '' } }

        post '/articles', params: invalid_params

        expect(response).to have_http_status(:unprocessable_entity)
      end
    end
  end

  describe 'authentication' do
    it 'requires authentication for create' do
      post '/articles', params: { article: { title: 'Test' } }

      expect(response).to have_http_status(:unauthorized)
    end

    it 'allows authenticated users to create' do
      user = create(:user)

      post '/articles',
        params: { article: { title: 'Test' } },
        headers: { 'Authorization' => "Bearer #{user.token}" }

      expect(response).to have_http_status(:created)
    end
  end
end
3. システムスペック(エンドツーエンド)

Capybara を使い、ブラウザー上でユーザーのワークフローをテストします。

RSpec.describe 'Article management', type: :system do
  before { driven_by(:selenium_chrome_headless) }

  scenario 'user creates an article' do
    visit new_article_path

    fill_in 'Title', with: 'My Article'
    fill_in 'Body', with: 'Article content'
    click_button 'Create Article'

    expect(page).to have_content('Article was successfully created')
    expect(page).to have_content('My Article')
  end

  scenario 'user edits an article' do
    article = create(:article, title: 'Original Title')

    visit article_path(article)
    click_link 'Edit'

    fill_in 'Title', with: 'Updated Title'
    click_button 'Update Article'

    expect(page).to have_content('Updated Title')
    expect(page).not_to have_content('Original Title')
  end

  # Test JavaScript interactions
  scenario 'user filters articles', js: true do
    create(:article, title: 'Ruby Article', category: 'ruby')
    create(:article, title: 'Python Article', category: 'python')

    visit articles_path

    select 'Ruby', from: 'filter'

    expect(page).to have_content('Ruby Article')
    expect(page).not_to have_content('Python Article')
  end
end

Factory Bot の統合

テストデータには FactoryBot を使用します。ファクトリーを spec/factories/ に定義し、バリエーションにはトレイトを使い、永続化が不要な場合は create より build を優先します。

ファクトリーの定義、トレイト、シーケンス、関連付け、ビルド戦略については、references/factory_bot.md を参照してください。

必須のマッチャー

カテゴリー例
等価性eq、eql、be、equal
真偽値be_truthy、be_falsy、be_nil、be_a
コレクションinclude、contain_exactly、match_array
変化change、raise_error、have_enqueued_job

マッチャーの完全なリファレンスについては、references/matchers.md を参照してください。

モック、スタブ、ダブル

テストダブルには double または instance_double(実際のクラスに照らして検証されるため、こちらを推奨)を使います。allow(obj).to receive(:method) でスタブを設定し、expect(obj).to receive(:method) で期待値を設定します。さらに、have_received を使うスパイで事後に検証します。

テストダブル、スタブ、メッセージの期待値、スパイについては、references/mocking.md を参照してください。

DRY なテスト手法

テストデータには let(遅延評価)と let!(即時評価)を、共通のセットアップには before フックを、再利用可能なテストグループには shared_examples を、再利用可能なセットアップブロックには shared_context を使います。テスト対象のオブジェクトには subject を優先して使います。

フック、let、共有サンプル、共有コンテキスト、subject について詳しくは、references/core_concepts.md を参照してください。

TDD ワークフロー

Red-Green-Refactor サイクル
  1. Red:まず失敗するテストを書きます
describe User do
  it 'has a full name' do
    user = User.new(first_name: 'John', last_name: 'Doe')
    expect(user.full_name).to eq('John Doe')
  end
end
# Fails: undefined method `full_name'
  1. Green:テストを通すための最小限のコードを書きます
class User
  def full_name
    "#{first_name} #{last_name}"
  end
end
# Passes!
  1. Refactor:テストが成功する状態を保ちながら、コードを改善します
テスト戦略

ユーザー向け機能では、まずシステムスペックから始めます。

  • ワークフロー全体をテストします
  • 最も高い信頼性を得られます
  • 実行に最も時間がかかります

API/コントローラーロジックには、リクエストスペックに切り替えます。

  • HTTP のやり取りをテストします
  • システムスペックより高速です
  • 認証、認可、エッジケースを網羅します

ビジネスロジックには、モデルスペックを使います。

  • 計算、バリデーション、スコープをテストします
  • 高速で、対象を絞れます
  • テストスイートの大部分を占めます

設定のベストプラクティス

spec/rails_helper.rb
require 'spec_helper'
ENV['RAILS_ENV'] ||= 'test'
require_relative '../config/environment'
abort("Run in production!") if Rails.env.production?
require 'rspec/rails'

# Auto-require support files
Dir[Rails.root.join('spec', 'support', '**', '*.rb')].sort.each { |f| require f }

RSpec.configure do |config|
  # Use transactional fixtures
  config.use_transactional_fixtures = true

  # Infer spec type from file location
  config.infer_spec_type_from_file_location!

  # Filter Rails backtrace
  config.filter_rails_from_backtrace!

  # Include FactoryBot methods
  config.include FactoryBot::Syntax::Methods

  # Include request helpers
  config.include RequestHelpers, type: :request

  # Capybara configuration for system specs
  config.before(:each, type: :system) do
    driven_by :selenium_chrome_headless
  end
end
spec/spec_helper.rb
RSpec.configure do |config|
  # Show detailed failure messages
  config.example_status_persistence_file_path = "spec/examples.txt"

  # Disable monkey patching (use expect syntax only)
  config.disable_monkey_patching!

  # Output warnings
  config.warnings = true

  # Profile slowest tests
  config.profile_examples = 10 if ENV['PROFILE']

  # Run specs in random order
  config.order = :random
  Kernel.srand config.seed
end

よくあるパターン

バックグラウンドジョブ、メーラー、ファイルアップロード、ページネーション、検索のテストについては、references/rails_testing.md を参照してください。

パフォーマンスのヒント

  1. 遅延読み込みには before ではなく let を使います

  2. ロジックのテストではデータベース呼び出しを避けます(モックを使います)

  3. 永続化が不要な場合は create ではなく build を使います

  4. 関連付けのある非永続化オブジェクトには build_stubbed を使います

  5. 時間のかかるテストにタグを付け、開発中は除外します:

    it 'slow test', :slow do
      # test code
    end
    
    # Run with: rspec --tag ~slow
    

各スペックタイプの使い分け

  • モデルスペック:ビジネスロジック、計算、バリデーション、スコープ
  • リクエストスペック:API エンドポイント、認証、認可、JSON レスポンス
  • システムスペック:ユーザーワークフロー、JavaScript のインタラクション、フォーム送信
  • メーラースペック:メールの内容、宛先、添付ファイル
  • ジョブスペック:バックグラウンドジョブのキューへの追加と実行
  • ヘルパースペック:ビューのヘルパーメソッド
  • ルーティングスペック:カスタムルート(通常は不要です)

クイックリファレンス

よく使うコマンド:

rspec                          # Run all specs
rspec spec/models              # Run model specs
rspec --tag ~slow              # Exclude slow specs
rspec --only-failures          # Rerun failures
rspec --format documentation   # Readable output
rspec --profile               # Show slowest specs

よく使うマッチャー:

  • eq(expected) - 値が等しいこと
  • be_truthy / be_falsy - 真偽値であること
  • include(item) - コレクションに含まれること
  • raise_error(Error) - 例外
  • change { }.by(n) - 状態の変化

よく使うスタブ:

  • allow(obj).to receive(:method) - メソッドをスタブ化
  • expect(obj).to receive(:method) - 呼び出しを期待
  • double('name', method: value) - ダブルを作成

リファレンスドキュメント

特定のトピックの詳細については、references ディレクトリを参照してください。

よくあるシナリオ

失敗するテストのデバッグ、複雑なクエリのテスト、コールバックのテストについては、references/rails_testing.mdを参照してください。

コメント