rspec-service-testing について
Ruby と Rails の開発者向けに、サービスクラスの RSpec テスト作成を支援するスキルです。公開契約の検証を重視し、テストの作成、実行、確認、修正を順に進めます。
主な機能
- 01公開契約に基づくサービスのテスト
- 02instance_double による単体テストの分離
- 03create によるデータベース統合テスト
- 04API レスポンス用ハッシュファクトリー
- 05テスト手順とチェックリスト
活用シーン
- 01サービスの成功・エラー経路のテスト
- 02単体テストとDB統合テストの使い分け
- 03API レスポンス用ハッシュデータの作成
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ midudev/ autoskills --skill rspec-service-testingインストール後、Claude Code で/rspec-service-testingを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
PATTERNS.mdassets/spec_examples.mdtesting_checklist.md詳細
RSpec サービスのテスト
spec/services/ 配下のサービスクラスのテストを書くときに、このスキルを使用します。
基本原則: 内部実装ではなく、公開されている契約(.call、.find、.search)をテストします。分離には instance_double を、統合テストには create を使用します。
ワークフロー:作成 → 実行 → 検証 → 修正
1. WRITE: Write the spec (happy path + error cases + edge cases)
2. RUN: bundle exec rspec spec/services/your_service_spec.rb
3. VERIFY: Confirm failures are for the right reason (not a typo or missing factory)
4. FIX: Implement or fix until the spec passes
5. SUITE: bundle exec rspec spec/services/ — verify no regressions
ステップ 1 のテストを作成し、正しい理由で失敗することを確認する前に、サービスを実装してはいけません。
クイックリファレンス
| 項目 | ルール |
|---|---|
| ファイルの場所 | spec/services/module_name/service_spec.rb |
| Subject | subject(:service_call) { described_class.call(params) } |
| 単体テストの分離 | 協調オブジェクトには instance_double を使用 |
| 統合テスト | DB を使用するテストには create を使用 |
| 複数のアサーション | aggregate_failures |
| 状態の検証 | change マッチャー |
| 時間に依存するテスト | travel_to |
| API レスポンス | FactoryBot のハッシュファクトリー(class: Hash) |
Spec のテンプレート
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe ModuleName::MainService do
describe '.call' do
subject(:service_call) { described_class.call(params) }
let(:shelter) { create(:shelter, :with_animals) }
let(:params) do
{ shelter: { shelter_id: shelter.id }, items: %w[TAG001 TAG002] }
end
context 'when input is valid' do
before { create(:animal, tag_number: 'TAG001', shelter:) }
it 'returns success' do
expect(service_call[:success]).to be true
end
end
context 'when shelter is not found' do
let(:params) { super().merge(shelter: { shelter_id: 999_999 }) }
it 'returns error response' do
expect(service_call[:success]).to be false
end
end
context 'when input is blank' do
let(:params) { { shelter: { shelter_id: nil }, items: [] } }
it 'returns error response with meaningful message' do
aggregate_failures do
expect(service_call[:success]).to be false
expect(service_call[:errors]).not_to be_empty
end
end
end
end
end
単体テストを分離するには instance_double を使用します。
let(:client) { instance_double(Api::Client) }
before { allow(client).to receive(:execute_query).and_return(api_response) }
統合テストには create を使用します。
let(:source_shelter) { create(:shelter, :with_animals) }
API レスポンス用の FactoryBot ハッシュファクトリー
API クライアントをテストする場合は、class: Hash と initialize_with を使用して、ハッシュ形式のレスポンスフィクスチャを作成します。最小限の例を示します。
FactoryBot.define do
factory :api_animal_response, class: Hash do
tag_number { 'TAG001' }
status { 'active' }
initialize_with { attributes.stringify_keys }
end
end
# In the spec:
let(:api_response) { build(:api_animal_response, tag_number: 'TAG002') }
パターン全体とファクトリーの配置に関するガイダンスは、PATTERNS.md を参照してください。
新しいテストファイルのチェックリスト
- メインの処理に対して
subjectを定義している - 単体テストには
instance_double、統合テストにはcreateを使用している - 各公開メソッドに対する正常系のテストがある
- エラーケースとエッジケース(空の入力、無効な参照、失敗)がある
- 該当する場合は部分的な成功シナリオがある
- 繰り返されるパターンに
shared_examplesを使用している - 複数アサーションのテストに
aggregate_failuresを使用している - 状態の検証に
changeマッチャーを使用している - エラーログ出力に対するロガーの期待値を設定している
よくある間違い
| 間違い | 正しい方法 |
|---|---|
| エラーケースのテストがない | 正常系だけでは誤った安心感につながります。必ず失敗ケースもテストしてください |
あらゆる場所で let! を使う | セットアップで値が必ず必要な場合を除き、遅延評価される let を使用します |
| ファクトリーのセットアップが大きすぎる | ファクトリーは最小限に保ち、テストに必要な属性だけを指定します |
| 動作が変わっていないのに実装変更で Spec が失敗する | リファクタリングで失敗するテストは、契約ではなく内部実装をテストしています |
関連スキル
| スキル | 組み合わせるタイミング |
|---|---|
| rspec-best-practices | 一般的な RSpec のスタイルと TDD の原則について |
| ruby-service-objects | テスト対象となるサービスの規約について |
| ruby-api-client-integration | API クライアント層のテストパターンについて |
| rails-engine-testing | エンジン固有のサービスをテストする場合 |
アセット
コメント
Markdown 対応