关于 rspec
面向 Ruby 和 Rails 项目的 RSpec 测试指导技能,供编写和维护测试的开发者使用。内容涵盖多种 spec 类型、测试替身、Factory Bot 及测试性能实践。
主要功能
- 01指导模型、请求和系统测试
- 02介绍 Factory Bot 测试数据策略
- 03说明匹配器、Mock 与 Stub
- 04提供 TDD 与测试分层建议
- 05涵盖 Rails 配置和性能实践
适用场景
- 01为 Rails 模型验证业务逻辑
- 02测试 API 请求、认证与响应
- 03通过浏览器验证用户工作流
- 04减少测试套件中的慢速用例
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ el-feo/ ai-context --skill rspec安装后在 Claude Code 中输入/rspec确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/best_practices.mdconfiguration.mdcore_concepts.mdfactory_bot.mdmatchers.mdmocking.mdrails_testing.md详细介绍
RSpec 测试技能
为 Ruby 和 Rails 应用编写全面 RSpec 测试的专家指南。本技能提供即时、可执行的测试策略,并附有针对复杂场景的深入参考资料。
快速入门
基本 RSpec 结构
# spec/models/user_spec.rb
RSpec.describe User, type: :model do
describe '#full_name' do
it 'returns the first and last name' do
user = User.new(first_name: 'John', last_name: 'Doe')
expect(user.full_name).to eq('John Doe')
end
end
end
核心概念:
describe:对相关测试(类、方法)进行分组context:描述特定场景it:单个测试示例expect:使用匹配器进行断言
运行测试
# Run all specs
bundle exec rspec
# Run specific file
bundle exec rspec spec/models/user_spec.rb
# Run specific line
bundle exec rspec spec/models/user_spec.rb:12
# Run with documentation format
bundle exec rspec --format documentation
# Run only failures from last run
bundle exec rspec --only-failures
核心测试模式
1. 模型规格测试
测试业务逻辑、验证、关联和方法:
RSpec.describe Article, type: :model do
# Test validations
describe 'validations' do
it { should validate_presence_of(:title) }
it { should validate_length_of(:title).is_at_most(100) }
end
# Test associations
describe 'associations' do
it { should belong_to(:author) }
it { should have_many(:comments) }
end
# Test instance methods
describe '#published?' do
context 'when publish_date is in the past' do
it 'returns true' do
article = Article.new(publish_date: 1.day.ago)
expect(article.published?).to be true
end
end
context 'when publish_date is in the future' do
it 'returns false' do
article = Article.new(publish_date: 1.day.from_now)
expect(article.published?).to be false
end
end
end
# Test scopes
describe '.recent' do
it 'returns articles from the last 30 days' do
old = create(:article, created_at: 31.days.ago)
recent = create(:article, created_at: 1.day.ago)
expect(Article.recent).to include(recent)
expect(Article.recent).not_to include(old)
end
end
end
2. 请求规格测试
测试整个技术栈中的 HTTP 请求和响应:
RSpec.describe 'Articles API', type: :request do
describe 'GET /articles' do
it 'returns all articles' do
create_list(:article, 3)
get '/articles'
expect(response).to have_http_status(:success)
expect(JSON.parse(response.body).size).to eq(3)
end
end
describe 'POST /articles' do
context 'with valid params' do
it 'creates a new article' do
article_params = { article: { title: 'New Article', body: 'Content' } }
expect {
post '/articles', params: article_params
}.to change(Article, :count).by(1)
expect(response).to have_http_status(:created)
end
end
context 'with invalid params' do
it 'returns errors' do
invalid_params = { article: { title: '' } }
post '/articles', params: invalid_params
expect(response).to have_http_status(:unprocessable_entity)
end
end
end
describe 'authentication' do
it 'requires authentication for create' do
post '/articles', params: { article: { title: 'Test' } }
expect(response).to have_http_status(:unauthorized)
end
it 'allows authenticated users to create' do
user = create(:user)
post '/articles',
params: { article: { title: 'Test' } },
headers: { 'Authorization' => "Bearer #{user.token}" }
expect(response).to have_http_status(:created)
end
end
end
3. 系统规格测试(端到端)
使用 Capybara 在浏览器中测试用户工作流:
RSpec.describe 'Article management', type: :system do
before { driven_by(:selenium_chrome_headless) }
scenario 'user creates an article' do
visit new_article_path
fill_in 'Title', with: 'My Article'
fill_in 'Body', with: 'Article content'
click_button 'Create Article'
expect(page).to have_content('Article was successfully created')
expect(page).to have_content('My Article')
end
scenario 'user edits an article' do
article = create(:article, title: 'Original Title')
visit article_path(article)
click_link 'Edit'
fill_in 'Title', with: 'Updated Title'
click_button 'Update Article'
expect(page).to have_content('Updated Title')
expect(page).not_to have_content('Original Title')
end
# Test JavaScript interactions
scenario 'user filters articles', js: true do
create(:article, title: 'Ruby Article', category: 'ruby')
create(:article, title: 'Python Article', category: 'python')
visit articles_path
select 'Ruby', from: 'filter'
expect(page).to have_content('Ruby Article')
expect(page).not_to have_content('Python Article')
end
end
Factory Bot 集成
使用 FactoryBot 创建测试数据。在 spec/factories/ 中定义工厂,使用 traits 创建不同变体;如果不需要持久化,优先使用 build,而非 create。
有关工厂定义、traits、序列、关联和构建策略,请参阅 references/factory_bot.md。
必备匹配器
| 类别 | 示例 |
|---|---|
| 相等性 | eq、eql、be、equal |
| 真值 | be_truthy、be_falsy、be_nil、be_a |
| 集合 | include、contain_exactly、match_array |
| 变化 | change、raise_error、have_enqueued_job |
完整的匹配器参考请参阅 references/matchers.md。
Mock、Stub 和 Double
使用 double 或 instance_double(优先使用,可针对真实类进行验证)创建测试替身。使用 allow(obj).to receive(:method) 设置 Stub,使用 expect(obj).to receive(:method) 设置预期,并通过 have_received 间谍事后验证。
有关测试替身、Stub、消息预期和间谍,请参阅 references/mocking.md。
DRY 测试技巧
使用 let(惰性)和 let!(即时)创建测试数据,使用 before 钩子共享设置,使用 shared_examples 复用测试组,并使用 shared_context 复用设置块。对于被测对象,优先使用 subject。
有关钩子、let、共享示例、共享上下文和 subject 的详细说明,请参阅 references/core_concepts.md。
TDD 工作流
Red-Green-Refactor 循环
- Red:先编写一个失败的测试
describe User do
it 'has a full name' do
user = User.new(first_name: 'John', last_name: 'Doe')
expect(user.full_name).to eq('John Doe')
end
end
# Fails: undefined method `full_name'
- Green:编写最少的代码使测试通过
class User
def full_name
"#{first_name} #{last_name}"
end
end
# Passes!
- Refactor:在保持测试通过的同时改进代码
测试策略
面向用户的功能应从系统规格测试开始:
- 测试完整工作流
- 信心最高
- 运行最慢
对于 API/控制器逻辑,转向请求规格测试:
- 测试 HTTP 交互
- 比系统规格测试快
- 覆盖身份验证、授权和边缘情况
对于业务逻辑,使用模型规格测试:
- 测试计算、验证和作用域
- 快速且聚焦
- 占测试套件的大部分
配置最佳实践
spec/rails_helper.rb
require 'spec_helper'
ENV['RAILS_ENV'] ||= 'test'
require_relative '../config/environment'
abort("Run in production!") if Rails.env.production?
require 'rspec/rails'
# Auto-require support files
Dir[Rails.root.join('spec', 'support', '**', '*.rb')].sort.each { |f| require f }
RSpec.configure do |config|
# Use transactional fixtures
config.use_transactional_fixtures = true
# Infer spec type from file location
config.infer_spec_type_from_file_location!
# Filter Rails backtrace
config.filter_rails_from_backtrace!
# Include FactoryBot methods
config.include FactoryBot::Syntax::Methods
# Include request helpers
config.include RequestHelpers, type: :request
# Capybara configuration for system specs
config.before(:each, type: :system) do
driven_by :selenium_chrome_headless
end
end
spec/spec_helper.rb
RSpec.configure do |config|
# Show detailed failure messages
config.example_status_persistence_file_path = "spec/examples.txt"
# Disable monkey patching (use expect syntax only)
config.disable_monkey_patching!
# Output warnings
config.warnings = true
# Profile slowest tests
config.profile_examples = 10 if ENV['PROFILE']
# Run specs in random order
config.order = :random
Kernel.srand config.seed
end
常见模式
有关后台作业、邮件程序、文件上传、分页和搜索的测试,请参阅 references/rails_testing.md。
性能提示
-
使用 let 代替 before,实现惰性加载
-
测试逻辑时避免数据库调用(使用 Mock)
-
如果不需要持久化,使用 build 代替 create
-
对于带关联的非持久化对象,使用 build_stubbed
-
为慢速测试添加标签,并在开发期间排除这些测试:
it 'slow test', :slow do # test code end # Run with: rspec --tag ~slow
何时使用各类 spec
- Model spec:业务逻辑、计算、验证、作用域
- Request spec:API 端点、身份验证、授权、JSON 响应
- System spec:用户工作流、JavaScript 交互、表单提交
- Mailer spec:邮件内容、收件人、附件
- Job spec:后台任务的入队和执行
- Helper spec:视图辅助方法
- Routing spec:自定义路由(通常不需要)
快速参考
最常用的命令:
rspec # Run all specs
rspec spec/models # Run model specs
rspec --tag ~slow # Exclude slow specs
rspec --only-failures # Rerun failures
rspec --format documentation # Readable output
rspec --profile # Show slowest specs
最常用的匹配器:
eq(expected)- 值相等be_truthy/be_falsy- 真值判断include(item)- 集合成员判断raise_error(Error)- 异常change { }.by(n)- 状态变化
最常用的桩:
allow(obj).to receive(:method)- 为方法设置桩expect(obj).to receive(:method)- 预期方法调用double('name', method: value)- 创建测试替身
参考文档
有关特定主题的详细信息,请参阅 references 目录:
- 核心概念 - Describe 块、contexts、钩子、subject、let
- 匹配器指南 - 完整的匹配器参考及示例
- 模拟与桩 - 测试替身、桩、间谍、消息预期
- Rails 测试 - Rails 专用的 spec 类型和辅助方法
- Factory Bot - 测试数据策略和模式
- 最佳实践 - 测试理念、模式和反模式
- 配置 - 设置、格式化器和优化
常见场景
有关调试失败的测试、测试复杂查询和测试回调的信息,请参阅 references/rails_testing.md。