关于 rspec-service-testing
面向 Ruby 和 Rails 开发者的服务类 RSpec 测试技能,强调验证公开契约,并采用先编写测试、再运行和修复的流程。
主要功能
- 01围绕公开契约编写服务测试
- 02使用 instance_double 隔离单元测试
- 03使用 create 编写数据库集成测试
- 04构建 API 响应哈希工厂
- 05提供测试流程与检查清单
适用场景
- 01测试服务的成功与错误路径
- 02区分单元测试和数据库集成测试
- 03为 API 响应构建哈希测试数据
安装
复制下面的命令,在终端中运行。
$
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 隔离协作者 |
| 集成测试 | 使用 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 |
| 工厂设置过于庞大 | 保持工厂精简——只包含测试所需的属性 |
| 实现变更但行为不变时,测试却失败 | 重构时会失败的测试测的是内部实现,而非契约 |
集成
| 技能 | 适用场景 |
|---|---|
| rspec-best-practices | 遵循通用 RSpec 风格和 TDD 规范 |
| ruby-service-objects | 了解被测服务所遵循的约定 |
| ruby-api-client-integration | 了解 API 客户端层测试模式 |
| rails-engine-testing | 测试引擎专属服务时 |
资源
评论
支持 Markdown