Rails Testing Patterns
Use standard RSpec and Minitest conventions for syntax, assertions, matchers, and Capybara DSL. This skill focuses on opinionated choices — what to test, which framework to use, and how to structure test data.
See patterns.md for decision guidance and non-obvious patterns.
Test Type Decision Matrix
| Test Type | When to Write | Speed | ROI Notes |
|-----------|--------------|-------|-----------|
| Unit (Model) | Business logic, validations, scopes, custom methods | Fast | Highest ROI — write first wherever models or services carry non-trivial logic |
| Request | API endpoints, auth flows, param handling | Medium | Highest ROI on the api delivery axis; prefer over controller specs in RSpec |
| Integration | Multi-step workflows spanning controllers | Medium | Valuable on the html delivery axis — exercises the full request/render cycle |
| System | Critical user journeys only (sign-up, checkout, onboarding) | Slow | Limit to 10-20 per app; never test CRUD forms with system tests |
| Mailer | Non-trivial email content, conditional delivery | Fast | Skip if mailer is just a default scaffold |
| Job | Idempotency, retry behavior, side effects | Fast | Always test jobs that touch external services |
Framework, Data, and Directory
Test framework, data strategy, and directory are orthogonal project facts, not architecture choices. A project with extracted service objects can use Minitest; an omakase app can use RSpec. Read them from the project-conventions fingerprint (Testing category) — framework (Minitest/RSpec), data (fixtures/factories), directory (test/ vs spec/). Never infer the framework from architecture.
Test emphasis does vary by Axis B — delivery:
| Delivery | First tests to write | System tests |
|----------|---------------------|--------------|
| html | Integration tests for key flows | Yes, for critical user journeys |
| api | Request specs | No — request specs cover it |
Anti-Patterns
| Anti-Pattern | Do Instead | Why |
|-------------|-----------|-----|
| Testing Rails internals (validates_presence_of works?) | Test your domain logic only | Rails is already tested |
| sleep in system tests | Rely on Capybara's built-in waiting (have_content, assert_text) | Sleep is flaky and slow |
| Shared mutable state between tests | Fresh state per test via let/setup | Test ordering bugs are the hardest to debug |
| Testing private methods directly | Test through the public interface | Couples tests to implementation |
| Huge factory/fixture with every field | Minimal defaults + traits/overrides | Reduces test fragility and speeds diagnosis |
| System tests for CRUD forms | Request/integration tests | 10x faster, same coverage for form submissions |
| Mocking the object under test | Mock collaborators, not the subject | Tests nothing useful |
Test Data Strategy
Use whichever strategy the project already uses — the project-conventions fingerprint reports fixtures vs factories. Guidance for each:
When the project uses fixtures:
- Fixtures are loaded once per test run (fast) and double as development seed data
- Use realistic, named fixtures:
jane:,admin:— neveruser_1:,user_2: - Use inline
Model.new(...)only for one-off edge cases not worth a fixture - Fixture files are the canonical source of test data — keep them curated
When the project uses factories:
- Minimal factory defaults — only required fields, everything else via traits
- Use
build(notcreate) whenever persistence isn't needed — dramatically faster - Use
sequencefor uniqueness constraints (emails, slugs) - Avoid deeply nested
createchains — if a test needs 4+createcalls, consider fixtures for that scenario - Reserve fixtures for truly static reference data (countries, currencies)
Edge Cases to Always Test
- Nil / blank / empty inputs
- Boundary values (0, -1, MAX)
- Unauthorized and forbidden access
- Invalid parameter combinations
- Concurrent modifications (optimistic locking, uniqueness races)
Output Format
When reporting on test quality, use:
## Test Analysis: [spec_or_test_file]
**Coverage Gaps:**
- [model/action] missing test for [scenario]
**Issues:**
- [severity] description
**Recommendations:**
1. actionable recommendation