关于 rails-testing
rails-testing 是用于编写和审查 Rails 应用测试的技能,采用 Minitest 和 fixtures,强调关注行为、保持测试确定性,并选择合适的测试层级。
主要功能
- 01Minitest 与 fixtures 规范
- 02以行为为中心的测试覆盖
- 03测试层级选择建议
- 04异步与外部边界测试
- 05授权和租户测试模式
适用场景
- 01审查 Rails 测试覆盖情况
- 02端到端测试用户工作流
- 03为授权问题添加回归测试
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ marckohlbrugge/ 37signals-skills --skill rails-testing安装后在 Claude Code 中输入/rails-testing确认已加载。
详细介绍
Rails 测试
适用于编写和审查测试的任务。模式参考 Campfire 和 Fizzy 的测试套件。
默认做法
- 使用 Minitest + fixtures。不使用 RSpec,也不使用 FactoryBot。
- 测试行为,而非实现细节。
- 保持测试确定且快速;使用
parallelize(workers: :number_of_processors)。 - 功能的测试应与功能在同一个 commit/PR 中提交,不提前,也不延后。安全修复始终要包含回归测试。
- 切勿为了便于测试而增加生产代码的复杂度(不得因测试损害设计)。
覆盖预算(37signals 实际投入的地方)
- 重点: 模型测试(领域不变量、concerns)和控制器/集成测试(完整请求周期、身份验证、格式)。
- 少量: 为关键的顺畅流程编写少数系统测试(一个冒烟测试即可覆盖注册→使用);仅为包含实际逻辑的作业编写作业测试。
- 不写: 视图测试、JS/Stimulus 单元测试、穷举式频道测试。UI 行为通过系统测试间接覆盖。
- 不要在多个层重复断言相同行为。
Fixtures
- 使用标签而非 ID 表示关系;使用 ERB 表示相对时间戳(
created_at: <%= 1.hour.ago %>)以及共享的计算值(重复使用一个 bcrypt 摘要)。 - 让
test/models中的结构与app/models对应:app/models/card/closeable.rb↔test/models/card/closeable_test.rb;共享 concerns 放在test/models/concerns/下。 - UUID 主键会打乱 fixture 顺序:在 fixtures 中生成由标签确定的 UUIDv7,以确保
.first/.last的顺序稳定,且运行时记录始终更新。 - 使用生产代码构建富内容 fixtures(
ActionText::Attachment.from_attachable(user).to_html),不要手写标记。
良好实践
- 使用系统/集成测试验证用户工作流;使用模型测试验证领域不变量。
- 对基于时间的逻辑使用
travel_to。 - 仅在边界处进行模拟/替身处理(外部 API、网络、时间、
SecureRandom);对外部 HTTP 使用 VCR——根据类名和测试名称自动命名 cassette,并在匹配时规范化时间戳。 - 在模型测试中,使用
perform_enqueued_jobs(only: SpecificJob)和assert_enqueued_with测试异步副作用,而不是对简单的作业类进行单元测试。 - 在一个断言中验证相关计数变化:
assert_difference({ -> { card.assignees.count } => -1, -> { Event.count } => +1 })。 - 控制器提供多种响应格式时,分别测试每种格式:
as: :turbo_stream(断言 stream 目标)和as: :json(状态码、Location 标头、响应正文)。 - 按层测试 Turbo/广播:模型测试使用
assert_turbo_stream_broadcasts,控制器测试使用assert_turbo_stream action:, target:,负向测试使用assert_no_turbo_stream_broadcasts。 - 授权测试要断言不可访问的情况:跨租户/角色访问应返回 403/404,不能只验证允许访问正常工作。
- 多租户套件:在 setup 中设置
Current.account(行为取决于操作者时还要设置Current.session);集成/系统测试设置default_url_options[:script_name];为身份验证路由提供untenanted { }helper。在 teardown 中清除Current。 - 使用
Rack::MockRequest单独测试中间件。 - 系统测试:在多用户场景中使用
using_session("Kevin");断言实时行为前等待 cable 连接;通过快速的 session-transfer helper 进行身份验证,将完整登录流程限制在一个冒烟测试中。 - 存在非事务性副作用(FTS 表)的套件,按 helper 选择退出事务:使用
self.use_transactional_tests = false并显式清理。 - 并行套件中,每个测试都要重置共享的全局状态(线程池、
ActionCable.server.pubsub、Current)。
警示信号
- 仅为便于测试而增加生产代码的复杂度。
- 过度模拟/替身处理应用内部代码。
- 在多个层重复测试相同行为。
- 因每个测试都进行不必要的 setup 而导致套件变慢(这正是 fixtures 的用途)。
- 为只有一行代码的作业类或简单委托编写单元测试。
- 手写 HTML 字符串,而生产渲染器/helper 可以自动保持同步。
- 不使用
travel_to的时间相关断言。
评论
支持 Markdown