test-service について
サービスオブジェクトの RSpec テストを作成するためのスキルです。分離、統合テストの準備、カバレッジの規約を示し、実装前の動作検証や回帰確認に役立ちます。
主な機能
- 01サービススペックの構成と subject
- 02instance_double による分離
- 03データベース統合テストの準備
- 04API レスポンス用ハッシュファクトリー
- 05エラーと境界条件のチェックリスト
活用シーン
- 01サービスオブジェクトの正常系と失敗系をテスト
- 02単体テストでサービスの依存先を分離
- 03サービススペックのカバレッジ不足を確認
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ igmarin/ rails-agent-skills --skill test-serviceインストール後、Claude Code で/test-serviceを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
PATTERNS.mdassets/spec_examples.mdtesting_checklist.md詳細
テストサービス
クイックリファレンス
| 項目 | ルール |
|---|---|
| ファイルの場所 | 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) |
HARD-GATE
DO NOT implement the service before step 1 is written and failing for the right reason.
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
コアプロセス
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) }
重要 — 協調オブジェクトは必ず instance_double を介してスタブ化する必要があります。3 つのパターンがあります。
- 依存性を注入する: パラメータで直接 double を渡します。
.newをスタブ化する: サービスが内部でインスタンス化する場合はallow(CarrierApi::Client).to receive(:new).and_return(client)を使用します。- クラスレベルのスタブを避ける:
allow(CarrierApi::Client).to receive(:notify)は使用しないでください — 常にインスタンスを double 化します。
統合テストには 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') }
新しいテストファイルのチェックリスト
- メインのアクションに対して
subjectが定義されている - ユニットには
instance_double/ 統合にはcreate - 各パブリックメソッドのハッピーパス
- エラーおよびエッジケース(空の入力、無効な参照、失敗)
- 該当する場合は部分成功のシナリオ
- 繰り返しパターンには
shared_examples - 複数アサーションのテストには
aggregate_failures - 状態の検証には
changeマッチャー
よくある間違い
| 間違い | 正しいアプローチ |
|---|---|
| エラーシナリオのテストがない | ハッピーパスと併せて常に失敗もテストする |
どこでも let! | セットアップに無条件で必要な値でない限り let(遅延評価)を使用する |
| 巨大なファクトリーセットアップ | ファクトリーは最小限に保つ — テストが必要とする属性のみ |
| 振る舞いが変わっていないリファクタリングで spec が壊れる | リファクタリングで壊れるテストは内部をテストしており、契約をテストしていない |
拡張リソース(プログレッシブディスクロージャー)
これらのファイルは、その特定の内容が必要な場合にのみ読み込んでください。
- PATTERNS.md — パターンカタログの全体とファクトリーの配置に関するガイダンスが必要な場合に使用します
- assets/spec_examples.md — 上記の spec テンプレートを超える追加の実例が必要な場合に使用します
- assets/testing_checklist.md — 完成したサービスの spec を完全性の観点でレビューする場合に使用します
出力スタイル
サービステストを完了する際、出力には以下を含める必要があります。
# Service Spec — [ServiceName]
## Spec File
- Path: spec/services/<module>/<service>_spec.rb
- Subject: `described_class.call(params)`
## Coverage
- Happy path: ✓ (<n> examples)
- Error cases: ✓ (<n> examples — list error classes/conditions)
- Edge cases: ✓ (<n> examples — blank input, boundary values)
- Isolation: instance_double for <collaborator list>
## TDD Gate
- RED: <failure message confirming missing behavior>
- GREEN: <all examples pass>
- Suite: <full spec/services/ suite status>
連携
| スキル | チェーンするタイミング |
|---|---|
| write-tests | 一般的な RSpec スタイルと TDD の規律のために |
| create-service-object | テスト対象のサービスの規約のために |
| integrate-api-client | API クライアント層のテストパターンのために |
| test-engine | エンジン固有のサービスをテストする場合に |
コメント
Markdown 対応