mcpField
R
rspec-service-testing

rspec-service-testing

github.com/midudev测试与质量7.0k57 次安装1 周前更新
代码仓库

关于 rspec-service-testing

面向 Ruby 和 Rails 开发者的服务类 RSpec 测试技能,强调验证公开契约,并采用先编写测试、再运行和修复的流程。

主要功能

  1. 01围绕公开契约编写服务测试
  2. 02使用 instance_double 隔离单元测试
  3. 03使用 create 编写数据库集成测试
  4. 04构建 API 响应哈希工厂
  5. 05提供测试流程与检查清单

适用场景

  1. 01测试服务的成功与错误路径
  2. 02区分单元测试和数据库集成测试
  3. 03为 API 响应构建哈希测试数据

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/midudev/autoskills --skill rspec-service-testing

安装后在 Claude Code 中输入/rspec-service-testing确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

PATTERNS.md
assets/
spec_examples.md
testing_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
Subjectsubject(: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