Community Ruby on Rails Testing Best Practices
Comprehensive testing guide for Ruby on Rails applications, maintained by Community. Contains 46 rules across 8 categories, prioritized by impact to guide automated test generation, review, and refactoring.
When to Apply
Reference these guidelines when:
-
Writing new RSpec specs for models, requests, system tests, or jobs
-
Setting up FactoryBot factories with traits and sequences
-
Writing Capybara system tests for user journeys
-
Testing background jobs with Sidekiq or Active Job
-
Reviewing test code for anti-patterns (mystery guests, flaky tests, slow specs)
-
Optimizing test suite performance and CI pipeline speed
-
Organizing test files, shared examples, and custom matchers
Rule Categories by Priority
Priority Category Impact Prefix
1 Test Design & Structure CRITICAL design-
2 Test Data Management CRITICAL data-
3 Model Testing HIGH model-
4 Request & Controller Testing HIGH request-
5 System & Acceptance Testing MEDIUM-HIGH system-
6 Async & Background Job Testing MEDIUM async-
7 Test Performance & Reliability MEDIUM perf-
8 Test Organization & Maintenance LOW-MEDIUM org-
Quick Reference
- Test Design & Structure (CRITICAL)
-
design-four-phase-test
-
Use four-phase test structure (setup, exercise, verify, teardown)
-
design-behavior-over-implementation
-
Test observable behavior, not internal implementation
-
design-one-assertion-per-test
-
One logical expectation per test for precise failure diagnosis
-
design-descriptive-test-names
-
Write test names that read like specifications
-
design-avoid-mystery-guest
-
Make all test data visible within the test itself
-
design-avoid-conditional-logic
-
No if/else or loops in test code
-
design-explicit-subject
-
Name subjects explicitly instead of using implicit subject
- Test Data Management (CRITICAL)
-
data-factory-traits
-
Use composable factory traits instead of separate factories
-
data-minimal-attributes
-
Specify only attributes relevant to the test
-
data-build-over-create
-
Prefer build/build_stubbed over create when persistence isn't needed
-
data-avoid-fixture-coupling
-
Use factories instead of shared fixtures
-
data-transient-attributes
-
Use transient attributes for complex factory setup
-
data-sequence-unique-values
-
Use sequences for uniqueness-constrained fields
- Model Testing (HIGH)
-
model-test-validations
-
Test validations with boundary cases, not just happy path
-
model-test-associations
-
Test associations explicitly including dependent behavior
-
model-test-scopes
-
Test scopes with matching and non-matching records
-
model-test-callbacks-sparingly
-
Test callback side effects, not callback existence
-
model-test-custom-methods
-
Test public methods with input/output pairs across scenarios
-
model-avoid-testing-framework
-
Don't test ActiveRecord or framework behavior
-
model-test-enums
-
Test enum transitions and generated scopes
- Request & Controller Testing (HIGH)
-
request-over-controller-specs
-
Use request specs over deprecated controller specs
-
request-test-response-status
-
Assert HTTP status codes explicitly
-
request-test-authentication
-
Test authentication boundaries for every protected endpoint
-
request-test-authorization
-
Test authorization for each role
-
request-test-params-validation
-
Test parameter validation and edge cases
-
request-json-response-structure
-
Assert JSON response structure for API endpoints
- System & Acceptance Testing (MEDIUM-HIGH)
-
system-page-objects
-
Encapsulate page interactions in page objects
-
system-use-accessible-selectors
-
Use accessible selectors over CSS/XPath
-
system-avoid-sleep
-
Never use sleep — rely on Capybara's built-in waiting
-
system-test-critical-paths
-
Reserve system tests for critical user journeys
-
system-database-state
-
Use truncation strategy for system test database cleanup
-
system-screenshot-on-failure
-
Capture screenshots on system test failure
- Async & Background Job Testing (MEDIUM)
-
async-separate-enqueue-from-perform
-
Test enqueue and perform separately
-
async-use-fake-mode-default
-
Default to Sidekiq fake mode globally
-
async-test-job-perform
-
Test job perform method directly
-
async-test-mailer-delivery
-
Test mailer delivery with enqueued mail matcher
-
async-test-after-commit
-
Account for transaction-aware job enqueuing in Rails 7.2+
- Test Performance & Reliability (MEDIUM)
-
perf-parallel-tests
-
Run tests in parallel across CPU cores
-
perf-database-strategy
-
Use transaction strategy for non-system tests
-
perf-profile-slow-specs
-
Profile and fix the slowest specs
-
perf-quarantine-flaky-tests
-
Quarantine flaky tests instead of retrying
-
perf-avoid-before-all-mutation
-
Never mutate state created in before(:all)
- Test Organization & Maintenance (LOW-MEDIUM)
-
org-avoid-deep-nesting
-
Limit context nesting to 3 levels
-
org-shared-examples-sparingly
-
Use shared examples only for true behavioral contracts
-
org-custom-matchers
-
Extract custom matchers for repeated domain assertions
-
org-file-structure-mirrors-app
-
Mirror app directory structure in spec directory
How to Use
Read individual reference files for detailed explanations and code examples:
-
Section definitions - Category structure and impact levels
-
Rule template - Template for adding new rules
Reference Files
File Description
references/_sections.md Category definitions and ordering
assets/templates/_template.md Template for new rules
metadata.json Version and reference information