关于 test-service
用于编写服务对象 RSpec 测试的技能,涵盖隔离、集成测试设置和覆盖范围规范,适合在实现前验证服务行为并检查回归。
主要功能
- 01服务测试结构与 subject
- 02使用 instance_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 |
| 集成 | 数据库测试使用 create |
| 多重断言 | aggregate_failures |
| 状态验证 | change 匹配器 |
| 时间相关 | travel_to |
| API 响应 | FactoryBot hash 工厂(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 进行 stub。三种模式:
- 注入依赖: 直接在 params 中传入 double。
- Stub
.new: 当服务内部实例化时,使用allow(CarrierApi::Client).to receive(:new).and_return(client)。 - 避免类级别 stub: 不要使用
allow(CarrierApi::Client).to receive(:notify)— 始终对实例进行 double。
集成测试使用 create:
let(:source_shelter) { create(:shelter, :with_animals) }
用于 API 响应的 FactoryBot Hash 工厂
测试 API 客户端时,使用 class: Hash 配合 initialize_with 来构建 hash 形态的响应 fixture。一个最小示例:
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! | 除非该值在 setup 中无条件必需,否则使用 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