Testing Guide¶
MedTracker includes comprehensive testing infrastructure to ensure code quality, performance, and accessibility.
Test Framework¶
The project uses RSpec with Capybara for system tests:
- RSpec: Behavior-driven testing framework
- Capybara: Integration testing for web applications
- VCR: Record and replay HTTP interactions
Running Tests¶
Full Test Suite¶
Run all tests:
bundle exec rspec
Specific Test Types¶
Run only specific types of tests:
# Model tests
bundle exec rspec spec/models
# Controller tests
bundle exec rspec spec/controllers
# System/Feature tests
bundle exec rspec spec/features
# Policy tests
bundle exec rspec spec/policies
Individual Test Files¶
Run a specific test file:
bundle exec rspec spec/models/prescription_spec.rb
Single Test¶
Run a specific test by line number:
bundle exec rspec spec/models/prescription_spec.rb:42
Test Structure¶
Tests are organized in the spec/ directory:
spec/
├── models/ # Model tests
├── controllers/ # Controller tests
├── features/ # System/integration tests
├── policies/ # Authorization policy tests
├── components/ # Phlex component tests
├── fixtures/ # Test data
├── support/ # Test helpers
└── rails_helper.rb # RSpec configuration
Writing Tests¶
Test-Driven Development (TDD)¶
MedTracker follows the Red-Green-Refactor cycle:
- Red: Write a failing test
- Green: Write minimal code to make it pass
- Refactor: Clean up while keeping tests green
Model Tests¶
Example model test:
require 'rails_helper'
RSpec.describe Prescription do
describe 'validations' do
it 'requires a medicine' do
prescription = Prescription.new(medicine: nil)
expect(prescription).not_to be_valid
expect(prescription.errors[:medicine]).to include("can't be blank")
end
end
describe '#active?' do
it 'returns true when prescription is within date range' do
prescription = Prescription.create!(
medicine: create(:medicine),
start_date: 1.day.ago,
end_date: 1.day.from_now
)
expect(prescription.active?).to be true
end
end
end
System Tests¶
Example system test with Capybara:
require 'rails_helper'
RSpec.describe 'Prescriptions', type: :feature do
it 'allows creating a new prescription' do
medicine = create(:medicine)
visit new_prescription_path
select medicine.name, from: 'Medicine'
fill_in 'Dosage', with: '500mg'
click_button 'Create Prescription'
expect(page).to have_content('Prescription created successfully')
expect(page).to have_content('500mg')
end
end
Policy Tests¶
Example authorization test:
require 'rails_helper'
require 'pundit/rspec'
RSpec.describe PrescriptionPolicy do
subject(:policy) { described_class.new(user, prescription) }
let(:prescription) { create(:prescription) }
context 'when user is an administrator' do
let(:user) { create(:user, role: 'administrator') }
it { is_expected.to permit_action(:update) }
it { is_expected.to permit_action(:destroy) }
end
end
Test Data¶
Fixtures¶
Test data is managed using Rails fixtures in spec/fixtures/:
# spec/fixtures/medicines.yml
ibuprofen:
name: Ibuprofen
generic_name: Ibuprofen
strength: 200mg
form: Tablet
paracetamol:
name: Paracetamol
generic_name: Acetaminophen
strength: 500mg
form: Tablet
Factory Pattern¶
When fixtures aren't sufficient, use the factory pattern:
# In tests
let(:medicine) { Medicine.create!(name: 'Aspirin', strength: '100mg') }
Test Coverage¶
Running with Coverage¶
Generate a coverage report:
COVERAGE=true bundle exec rspec
Coverage reports are generated in coverage/ directory. Open coverage/index.html to view detailed coverage information.
Coverage Goals¶
- Overall Coverage: Aim for >80%
- Models: Aim for >90%
- Critical Paths: Aim for 100%
Continuous Integration¶
Tests run automatically on every pull request via GitHub Actions.
CI Pipeline¶
- Lint: RuboCop checks code style
- Security: Brakeman scans for vulnerabilities
- Tests: Full RSpec suite
- Lighthouse: Performance and accessibility audits
View the CI configuration in .github/workflows/ci.yml.
Lighthouse Audits¶
MedTracker includes automated Lighthouse audits for performance, accessibility, and best practices.
Running Locally¶
First, start the development server:
task dev:up
Then run Lighthouse:
# Run audit on dashboard
task lighthouse:run
# Run on a specific page
task lighthouse:run URL=http://localhost:3000/medicines
# View score summary
task lighthouse:summary
# List failed audits
task lighthouse:failed-audits
Lighthouse Thresholds¶
CI enforces the following minimum scores:
| Category | Threshold |
|---|---|
| Performance | 70% |
| Accessibility | 85% |
| Best Practices | 85% |
Lighthouse Reports¶
Reports are: - Automatically generated on every CI run - Uploaded as artifacts - Retained for 30 days - Available in the GitHub Actions interface
Interpreting Results¶
Review Lighthouse reports for:
- Performance: Page load times, Time to Interactive
- Accessibility: ARIA attributes, color contrast, keyboard navigation
- Best Practices: HTTPS usage, console errors, image optimization
- SEO: Meta tags, structured data
Docker Testing¶
Run tests in a containerized environment:
# Run full test suite
docker compose -f docker-compose.test.yml up --abort-on-container-exit
# Run specific tests
./run test spec/models
Debugging Tests¶
Interactive Debugging¶
Add a breakpoint in your test:
require 'debug'
it 'does something' do
binding.break # Debugger will pause here
expect(something).to be_truthy
end
Screenshot Debugging¶
For system tests, capture screenshots on failure:
it 'shows the form', :js do
visit new_prescription_path
# Test fails, screenshot saved automatically
end
Screenshots are saved to tmp/capybara/.
Database Inspection¶
Inspect the database during tests:
it 'creates a record' do
# Pause test to inspect database
binding.break
# Check data with: Prescription.all
end
Performance Testing¶
Profiling¶
Profile slow tests:
bundle exec rspec --profile 10
This shows the 10 slowest tests.
Database Queries¶
Monitor database queries in tests:
it 'performs efficiently' do
expect {
Prescription.active.includes(:medicine).to_a
}.to make_database_queries(count: 2)
end
Best Practices¶
- Descriptive Names: Use clear test descriptions
- One Assertion: Focus tests on single behaviors
- Arrange-Act-Assert: Structure tests clearly
- Test Behavior: Test outcomes, not implementation
- Use Fixtures: Leverage shared test data
- Mock External Services: Use VCR for HTTP calls
- Clean Database: Tests should not depend on order
- Fast Tests: Keep tests fast with proper setup
Common Issues¶
Flaky Tests¶
If tests fail intermittently:
- Check for timing issues in system tests
- Ensure database is properly cleaned between tests
- Look for order-dependent tests
Slow Tests¶
If tests are slow:
- Use database transactions instead of truncation
- Minimize system test usage
- Stub external HTTP calls
- Profile and optimize slow tests
Database Pollution¶
If tests interfere with each other:
- Ensure DatabaseCleaner is configured
- Use database transactions
- Reset database state in
beforehooks