mcpField
R
rspec-coder

rspec-coder

github.com/majesticlabs-dev测试与质量5055 次安装7 周前更新
代码仓库

关于 rspec-coder

面向编写 RSpec 测试的开发者,提供 Rails 项目规范及组织规格、使用 fixtures、匹配器和模拟对象的示例。强调关注行为、相互独立,并覆盖正常情况与边缘情况。

主要功能

  1. 01AAA 结构与行为导向测试
  2. 02RSpec 文件组织和命名规范
  3. 03fixtures、subject 与 let 用法
  4. 04模拟、存根及匹配器示例
  5. 05常见 Rails 组件的覆盖指导

适用场景

  1. 01按清晰的上下文编写模型和服务规格
  2. 02用存根和调用期望测试外部调用
  3. 03使用 Shoulda Matchers 检查验证与关联
  4. 04检查规格是否覆盖错误及边缘情况

安装

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

$npx skills add https://github.com/majesticlabs-dev/majestic-marketplace --skill rspec-coder

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

包含的文件

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

references/
anti-patterns.md
matchers.md
patterns.md

详细介绍

RSpec 编码器

核心理念

  • AAA 模式:采用 Arrange-Act-Assert(准备-执行-断言)结构,清晰明了
  • 关注行为,而非实现:测试代码的行为,而不是实现方式
  • 隔离性:测试应相互独立
  • 描述性命名:代码块应清楚说明其行为
  • 覆盖率:测试正常路径和边界情况
  • 快速测试:尽量减少数据库操作
  • Fixtures:使用 fixtures 设置常用数据
  • Shoulda Matchers:用于验证和关联

关键约定

❌ 不要添加 require 'rails_helper'

RSpec 会通过 .rspec 配置导入。手动添加是多余的。

# ✅ GOOD - no require needed
RSpec.describe User do
  # ...
end
❌ 不要添加冗余的 Spec 类型

RSpec 会根据文件位置自动推断类型。

# ✅ GOOD - type inferred from spec/models/ location
RSpec.describe User do
  # ...
end
✅ 使用不带前导 :: 的命名空间
# ✅ GOOD - no leading double colons
RSpec.describe DynamicsGp::ERPSynchronizer do
  # ...
end

测试组织

文件结构
  • spec/models/ - 模型单元测试
  • spec/services/ - 服务对象测试
  • spec/controllers/ - 控制器测试
  • spec/requests/ - 请求规格(API 测试)
  • spec/mailers/ - 邮件发送器测试
  • spec/jobs/ - 后台作业测试
  • spec/fixtures/ - 测试数据
  • spec/support/ - 辅助模块和共享示例
  • spec/rails_helper.rb - Rails 专用配置
使用 describe 和 context
代码块用途示例
describe按方法/类分组describe "#process"
context按条件分组context "when user is admin"
RSpec.describe OrderProcessor do
  describe "#process" do
    context "with valid payment" do
      # success tests
    end

    context "with invalid payment" do
      # failure tests
    end
  end
end

Subject 和 Let

详细示例请参见 references/patterns.md。

模式用例
subject(:name) { ... }要测试的主要对象/方法
let(:name) { ... }延迟求值并缓存的数据
let!(:name) { ... }立即求值(在每项测试之前)
RSpec.describe User do
  describe "#full_name" do
    subject(:full_name) { user.full_name }
    let(:user) { users(:alice) }

    it { is_expected.to eq("Alice Smith") }
  end
end

Fixtures

详细示例请参见 references/patterns.md。

# spec/fixtures/users.yml
alice:
  name: Alice Smith
  email: [email protected]
  admin: false
RSpec.describe User do
  fixtures :users

  it "validates email" do
    expect(users(:alice)).to be_valid
  end
end

模拟和桩替换

详细示例请参见 references/patterns.md。

方法用途
allow(obj).to receive(:method)桩替换返回值
expect(obj).to receive(:method)验证调用是否发生
# Stubbing external service
allow(PaymentGateway).to receive(:charge).and_return(true)

# Verifying method called
expect(UserMailer).to receive(:welcome_email).with(user)

Matcher 快速参考

完整参考请参见 references/matchers.md。

必备 Matchers
# Equality
expect(value).to eq(expected)

# Truthiness
expect(obj).to be_valid
expect(obj).to be_truthy

# Change
expect { action }.to change { obj.status }.to("completed")
expect { action }.to change(Model, :count).by(1)

# Errors
expect { action }.to raise_error(SomeError)

# Collections
expect(array).to include(item)
expect(array).to be_empty
Shoulda Matchers
# Validations
it { is_expected.to validate_presence_of(:name) }
it { is_expected.to validate_uniqueness_of(:email) }

# Associations
it { is_expected.to have_many(:posts) }
it { is_expected.to belong_to(:account) }

AAA 模式

将所有测试组织为 Arrange-Act-Assert(准备-执行-断言):

describe "#process_refund" do
  subject(:process_refund) { processor.process_refund }

  let(:order) { orders(:completed_order) }
  let(:processor) { described_class.new(order) }

  it "updates order status" do
    process_refund  # Act
    expect(order.reload.status).to eq("refunded")  # Assert
  end

  it "credits user account" do
    expect { process_refund }  # Act
      .to change { order.user.reload.account_balance }  # Assert
      .by(order.total)
  end
end

测试覆盖率标准

测试内容
类型测试内容
模型验证、关联、作用域、回调、方法
服务正常路径、异常路径、边界情况、外部集成
控制器状态码、响应格式、身份验证、重定向
作业执行、重试逻辑、错误处理、幂等性
覆盖率示例
RSpec.describe User do
  fixtures :users

  describe "validations" do
    subject(:user) { users(:valid_user) }

    it { is_expected.to validate_presence_of(:name) }
    it { is_expected.to validate_presence_of(:email) }
    it { is_expected.to validate_uniqueness_of(:email).case_insensitive }
  end

  describe "associations" do
    it { is_expected.to have_many(:posts).dependent(:destroy) }
  end

  describe "#full_name" do
    subject(:full_name) { user.full_name }
    let(:user) { User.new(first_name: "Alice", last_name: "Smith") }

    it { is_expected.to eq("Alice Smith") }

    context "when last name is missing" do
      let(:user) { User.new(first_name: "Alice") }
      it { is_expected.to eq("Alice") }
    end
  end
end

反模式

详细示例请参见 references/anti-patterns.md。

反模式不良之处
require 'rails_helper'多余,通过 .rspec 加载
type: :model多余,根据文件位置推断
命名空间前导 ::违反 RuboCop 风格
空测试主体造成虚假的信心
测试私有方法与实现耦合
不使用 fixtures测试速度慢
不使用 shoulda验证测试冗长

最佳实践检查清单

关键约定:

  • 不添加 require 'rails_helper'
  • 不添加冗余的 spec 类型
  • 使用不带前导 :: 的命名空间

测试组织:

  • 使用 describe 描述方法/类
  • 使用 context 描述条件
  • 嵌套层级最多 3 层

测试数据:

  • 使用 fixtures(而非 factories)
  • 使用 let 定义延迟加载的数据
  • 使用 subject 指定要测试的方法

断言:

  • 使用 Shoulda matchers 验证
  • 使用 Shoulda matchers 检查关联
  • 使用 change matcher 检查状态变化

覆盖率:

  • 已测试正常路径
  • 已测试异常路径
  • 已覆盖边界情况

快速参考

# Minimal spec file
RSpec.describe User do
  fixtures :users

  describe "#full_name" do
    subject(:full_name) { user.full_name }
    let(:user) { users(:alice) }

    it { is_expected.to eq("Alice Smith") }
  end

  describe "validations" do
    subject(:user) { users(:alice) }

    it { is_expected.to validate_presence_of(:name) }
    it { is_expected.to have_many(:posts) }
  end
end

评论

支持 Markdown