rspec について
Ruby と Rails のプロジェクトでテストを書く開発者向けの RSpec ガイドスキルです。複数の spec 種別、テストダブル、Factory Bot、テスト性能の指針を扱います。
主な機能
- 01モデル、リクエスト、システム spec の指針
- 02Factory Bot によるテストデータ戦略
- 03マッチャー、モック、スタブの解説
- 04TDD とテスト階層化の指針
- 05Rails 設定と性能改善の実践
活用シーン
- 01Rails モデルのビジネスロジックをテスト
- 02API リクエスト、認証、レスポンスをテスト
- 03ブラウザーでユーザーワークフローを検証
- 04テストスイートの遅いテストを削減
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ el-feo/ ai-context --skill rspecインストール後、Claude Code で/rspecを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/best_practices.mdconfiguration.mdcore_concepts.mdfactory_bot.mdmatchers.mdmocking.mdrails_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 サイクル
- 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'
- Green:テストを通すための最小限のコードを書きます
class User
def full_name
"#{first_name} #{last_name}"
end
end
# Passes!
- 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 を参照してください。
パフォーマンスのヒント
-
遅延読み込みには before ではなく let を使います
-
ロジックのテストではデータベース呼び出しを避けます(モックを使います)
-
永続化が不要な場合は create ではなく build を使います
-
関連付けのある非永続化オブジェクトには build_stubbed を使います
-
時間のかかるテストにタグを付け、開発中は除外します:
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 ディレクトリを参照してください。
- 基本概念 - describe ブロック、context、フック、subject、let
- マッチャーガイド - 例を含むマッチャーの完全なリファレンス
- モックとスタブ - テストダブル、スタブ、スパイ、メッセージの期待値
- Rails テスト - Rails 固有のスペックタイプとヘルパー
- Factory Bot - テストデータの戦略とパターン
- ベストプラクティス - テストの考え方、パターン、アンチパターン
- 設定 - セットアップ、フォーマッター、最適化
よくあるシナリオ
失敗するテストのデバッグ、複雑なクエリのテスト、コールバックのテストについては、references/rails_testing.mdを参照してください。