Loading...
Loading...
Use when writing RSpec tests for service objects, API clients, orchestrators, or business logic in spec/services/. Covers instance_double, FactoryBot hash factories, shared_examples, subject/let blocks, context/describe structure, aggregate_failures, change matchers, travel_to, and error scenario testing.
npx skill4agent add igmarin/rails-agent-skills rspec-service-testingspec/services/.call.find.searchinstance_doublecreate1. 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| Aspect | Rule |
|---|---|
| File location | |
| Subject | |
| Unit isolation | |
| Integration | |
| Multi-assertion | |
| State verification | |
| Time-dependent | |
| API responses | FactoryBot hash factories ( |
# 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
endinstance_doublelet(:client) { instance_double(Api::Client) }
before { allow(client).to receive(:execute_query).and_return(api_response) }createlet(:source_shelter) { create(:shelter, :with_animals) }class: Hashinitialize_withsubjectinstance_doublecreateshared_examplesaggregate_failureschange| Mistake | Correct approach |
|---|---|
| No error scenario tests | Happy path only = false confidence — always test failures |
| Use |
| Huge factory setup | Keep factories minimal — only attributes required for the test |
| Spec breaks when implementation changes but behavior is unchanged | Tests that break on refactoring are testing internals, not contracts |
| Skill | When to chain |
|---|---|
| rspec-best-practices | For general RSpec style and TDD discipline |
| ruby-service-objects | For the service conventions being tested |
| ruby-api-client-integration | For API client layer testing patterns |
| rails-engine-testing | When testing engine-specific services |