mcpField
M
minitest-coder

minitest-coder

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

关于 minitest-coder

minitest-coder 是用于在 Rails 项目中编写和组织 Minitest 测试的技能指南,面向 Rails 开发者。内容涵盖测试风格、fixtures、断言、覆盖范围,以及保持测试清晰易维护的模式。

主要功能

  1. 01传统与 spec 风格测试
  2. 02AAA 结构与行为导向测试
  3. 03Rails 测试文件组织
  4. 04fixtures、stub 与 mock
  5. 05断言和覆盖范围指导
  6. 06进阶模式与反模式

适用场景

  1. 01为 Rails 模型和服务编写测试
  2. 02为测试场景选择 Minitest 风格
  3. 03检查测试结构与覆盖范围

安装

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

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

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

包含的文件

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

references/
advanced-patterns.md
anti-patterns.md
spec-patterns.md
testing-tips.md

详细介绍

Minitest 编码指南

核心理念

  • AAA 模式:采用 Arrange-Act-Assert(准备、执行、断言)结构,清晰明了
  • 关注行为,而非实现:测试代码的行为,而不是实现方式
  • 隔离性:测试应彼此独立
  • 描述性名称:使用清晰的测试描述
  • 覆盖率:测试正常路径和边缘情况
  • 快速测试:尽量减少数据库操作
  • Fixtures:使用 fixtures 提供测试数据

Minitest 风格

风格最适用于语法
传统风格简单的单元测试test "description"
Spec 风格带上下文的复杂场景使用 let/subject 的 describe/it
传统风格
class UserTest < ActiveSupport::TestCase
  test "validates presence of name" do
    user = User.new
    assert_not user.valid?
    assert_includes user.errors[:name], "can't be blank"
  end
end
Spec 风格
class UserTest < ActiveSupport::TestCase
  describe "#full_name" do
    subject { user.full_name }
    let(:user) { User.new(first_name: "Buffy", last_name:) }

    describe "with last name" do
      let(:last_name) { "Summers" }

      it "returns full name" do
        assert_equal "Buffy Summers", subject
      end
    end
  end
end

测试组织

文件结构
  • test/models/ - 模型单元测试
  • test/services/ - 服务对象测试
  • test/integration/ - 全栈测试
  • test/mailers/ - Mailer 测试
  • test/jobs/ - 后台作业测试
  • test/fixtures/ - 测试数据
  • test/test_helper.rb - 配置
命名约定
  • 与应用结构对应:app/models/user.rb → test/models/user_test.rb
  • 使用完整限定的命名空间:class Users::ProfileServiceTest
  • 不要添加 require 'test_helper'(会自动导入)

Spec 风格模式

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

模式使用场景
subject { ... }正在测试的方法
let(:name) { ... }延迟求值的数据
describe "context"将相关测试分组(最多 3 层)
before { ... }复杂的初始化设置
describe "#process" do
  subject { processor.process }
  let(:processor) { OrderProcessor.new(order) }
  let(:order) { orders(:paid_order) }

  it "succeeds" do
    assert subject.success?
  end
end

Fixtures

# test/fixtures/users.yml
alice:
  name: Alice Smith
  email: [email protected]
  created_at: <%= 2.days.ago %>
class UserTest < ActiveSupport::TestCase
  fixtures :users

  test "validates uniqueness" do
    duplicate = User.new(email: users(:alice).email)
    assert_not duplicate.valid?
  end
end

模拟与桩

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

方法用途
Object.stub :method, value模拟返回值
Minitest::Mock.new验证方法调用
test "processes payment" do
  PaymentGateway.stub :charge, true do
    processor = OrderProcessor.new(order)
    assert processor.process
  end
end

断言速查

基本断言
# Boolean
assert user.valid?
assert_not user.admin?

# Equality
assert_equal "Alice", user.name
assert_nil user.deleted_at

# Collections
assert_includes users, admin_user
assert_empty order.items

# Exceptions
assert_raises ActiveRecord::RecordInvalid do
  user.save!
end
Rails 断言
# Changes
assert_changes -> { user.reload.status }, to: "active" do
  user.activate!
end

assert_difference "User.count", 1 do
  User.create(name: "Charlie")
end

# Responses
assert_response :success
assert_redirected_to user_path(user)

AAA 模式

test "processes refund" do
  # Arrange
  order = orders(:completed_order)
  original_balance = order.user.account_balance

  # Act
  result = order.process_refund

  # Assert
  assert result.success?
  assert_equal "refunded", order.reload.status
end

使用 subject 的 Spec 风格:

describe "#process_refund" do
  subject { order.process_refund }
  let(:order) { orders(:completed_order) }

  it "updates status" do
    subject
    assert_equal "refunded", order.reload.status
  end

  it "credits user" do
    assert_changes -> { order.user.reload.account_balance }, by: order.total do
      subject
    end
  end
end

测试覆盖标准

类型测试内容
模型验证、关联、作用域、回调、方法
服务正常路径、异常路径、边缘情况、外部集成
控制器状态码、重定向、参数处理
作业执行、重试逻辑、错误处理
覆盖率示例
class UserTest < ActiveSupport::TestCase
  # Validations
  test "validates presence of name" do
    user = User.new(email: "[email protected]")
    assert_not user.valid?
    assert_includes user.errors[:name], "can't be blank"
  end

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

    it "returns full name" do
      assert_equal "Alice Smith", subject
    end

    describe "without last name" do
      let(:user) { User.new(first_name: "Alice") }

      it "returns first name only" do
        assert_equal "Alice", subject
      end
    end
  end
end

高级模式

有关 37signals 经过生产环境验证的模式的详细示例,请参见 references/advanced-patterns.md。

模式解决的问题
Current.account fixtures多租户 URL 隔离
验证断言的辅助方法尽早失败并提供清晰的消息
确定性 UUID可预测的 fixture 排序
VCR 时间戳过滤可重复使用的 API 录制文件
基于线程的并发检测竞态条件
适配器感知的辅助方法SQLite/MySQL 兼容性

反模式

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

反模式不妥之处
require 'test_helper'会自动导入
嵌套层级 >3输出难以阅读
用 @ivars 替代 let状态泄漏
缺少 subject代码重复
assert x.include?(y)应使用 assert_includes
测试私有方法与实现耦合
不使用 fixtures测试速度慢

最佳实践清单

组织结构:

  • 文件与应用结构保持一致
  • 不添加 require 'test_helper'
  • 使用完全限定的命名空间

风格选择:

  • 简单测试使用传统风格
  • 复杂上下文使用 Spec 风格
  • 嵌套层级最多为 3 层

测试数据:

  • 使用 fixtures(而非 factories)
  • 使用 let 共享数据
  • 使用 subject 指定被测方法

断言:

  • 使用正确的断言方法
  • 使用 Rails 辅助方法(assert_changes、assert_difference)
  • 测试行为,而非实现

覆盖范围:

  • 测试成功路径
  • 测试失败路径
  • 覆盖边界情况

何时选择不同风格

传统风格:简单验证、直接明了的测试、没有共享设置

Spec 风格:多个上下文、需要惰性求值、嵌套场景、可复用的 subject

如果能提升清晰度,可以在同一个文件中混用两种风格。

评论

支持 Markdown