Files
motovaultpro/docs/testing.md
2025-08-23 10:20:03 -05:00

291 lines
6.7 KiB
Markdown

# Testing Guide
Comprehensive testing strategy for MotoVaultPro Modified Feature Capsule architecture.
## Testing Philosophy
Each feature capsule contains complete, isolated test suites with no cross-feature dependencies.
## Test Structure
### Per Feature Organization
```
backend/src/features/[name]/tests/
├── fixtures/ # Test data
├── unit/ # Isolated unit tests
│ ├── [name].service.test.ts
│ └── [external].client.test.ts
└── integration/ # Full API tests
└── [name].integration.test.ts
```
## Docker Testing Workflow
### Primary Test Command
```bash
# Run all tests in containers
make test
```
This executes: `docker-compose exec backend npm test`
### Feature-Specific Testing
```bash
# Test single feature (complete isolation)
make shell-backend
npm test -- features/vehicles
# Test specific test type
npm test -- features/vehicles/tests/unit
npm test -- features/vehicles/tests/integration
# Test with coverage
npm test -- features/vehicles --coverage
```
### Test Environment Setup
1. **Container-Based**: All tests run inside Docker containers
2. **Test Database**: Isolated test database per feature
3. **Mock External APIs**: No real API calls during testing
4. **Cleanup**: Automatic test data cleanup after each test
## Test Types
### Unit Tests
**Location**: `features/[name]/tests/unit/`
**Purpose**: Test business logic in isolation
**Mocking**: All external dependencies mocked
Example: `vehicles.service.test.ts`
- Tests VIN validation logic
- Tests vehicle creation with mocked vPIC responses
- Tests caching behavior with mocked Redis
- Tests error handling paths
### Integration Tests
**Location**: `features/[name]/tests/integration/`
**Purpose**: Test complete API workflows
**Database**: Real test database with transactions
Example: `vehicles.integration.test.ts`
- Tests complete POST /api/vehicles workflow
- Tests authentication middleware
- Tests database persistence
- Tests error responses
### Test Fixtures
**Location**: `features/[name]/tests/fixtures/`
**Purpose**: Reusable test data
**Format**: JSON files with valid test objects
Example: `vehicles.fixtures.json`
```json
{
"validVehicle": {
"vin": "1HGBH41JXMN109186",
"nickname": "Test Honda",
"color": "Blue"
},
"vpicResponse": {
"Make": "Honda",
"Model": "Civic",
"ModelYear": "2021"
}
}
```
## Testing Commands Reference
### Development Testing
```bash
# Enter backend container
make shell-backend
# Run all tests
npm test
# Run specific feature
npm test -- features/vehicles
npm test -- features/fuel-logs
npm test -- features/maintenance
npm test -- features/stations
# Run with file watching
npm run test:watch
# Run single test file
npm test -- vehicles.service.test.ts
# Run tests matching pattern
npm test -- --testNamePattern="VIN validation"
```
### Coverage Reports
```bash
# Generate coverage for specific feature
npm test -- features/vehicles --coverage
# View coverage report
open coverage/lcov-report/index.html
```
### Container Management
```bash
# Restart containers with fresh database
make rebuild
# View test logs
make logs-backend
# Clean all test data
make clean && make dev
```
## Test Configuration
### Jest Configuration
**File**: `backend/jest.config.js`
**Setup**: TypeScript support, test environment
**Coverage**: Exclude node_modules, include src only
### Database Testing
- **Test DB**: Same as development (motovaultpro)
- **Transactions**: Each test runs in transaction, rolled back after
- **Isolation**: Tests cannot interfere with each other
- **Seeding**: Minimal seed data, test-specific fixtures
### Mock Strategy
- **External APIs**: Completely mocked (vPIC, Google Maps)
- **Database**: Real database with transactions
- **Redis**: Mocked for unit tests, real for integration
- **Auth**: Mocked JWT tokens for protected endpoints
## Test Data Management
### Fixtures Strategy
```javascript
// In test files
import fixtures from '../fixtures/vehicles.fixtures.json';
describe('Vehicle Service', () => {
it('should create vehicle', async () => {
const result = await vehicleService.create(
fixtures.validVehicle,
'user123'
);
expect(result.make).toBe('Honda');
});
});
```
### Database Seeding
```javascript
beforeEach(async () => {
// Clean slate for each test
await db.query('TRUNCATE TABLE vehicles CASCADE');
// Insert test-specific data
await db.query('INSERT INTO vehicles ...', testData);
});
```
## Debugging Tests
### Debug Single Test
```bash
# Run specific test with debugging
npm test -- --testNamePattern="should create vehicle" --verbose
# Debug integration test
npm test -- features/vehicles/tests/integration --detectOpenHandles
```
### Common Issues
#### Container Connection Issues
```bash
# Check container health
make logs-backend
# Restart with fresh state
make rebuild
```
#### Database Connection Issues
```bash
# Check postgres container
docker-compose logs postgres
# Reset database
make clean && make dev
```
#### Test Timeout Issues
```bash
# Increase timeout in jest config
# Or debug hanging connections
npm test -- --detectOpenHandles
```
## Continuous Integration
### Pre-commit Testing
All tests must pass before commits:
```bash
# Run linting and tests
npm run lint
npm test
# In Docker environment
make test
```
### Feature Development Workflow
1. **Write tests first**: TDD approach preferred
2. **Run tests continuously**: Use `npm run test:watch`
3. **Test in containers**: Always verify with `make test`
4. **Check coverage**: Ensure new code is covered
5. **Integration last**: Run full test suite before PR
## Test Performance
### Parallel Execution
- Jest runs tests in parallel by default
- Feature isolation allows true parallel testing
- No shared state between feature tests
### Test Speed Optimization
- **Unit tests**: Fast (< 1 second per test)
- **Integration tests**: Medium (< 5 seconds per test)
- **Full suite**: Target < 30 seconds total
### Database Optimization
- Use transactions for rollback (faster than truncate)
- Minimal fixture data
- Avoid complex joins in test setup
## Error Testing Strategy
### Expected Error Cases
```javascript
describe('Error Handling', () => {
it('should handle invalid VIN', async () => {
await expect(
vehicleService.create({ vin: 'INVALID' }, 'user123')
).rejects.toThrow('Invalid VIN format');
});
it('should handle vPIC API failure', async () => {
mockVpicClient.decode.mockRejectedValue(new Error('API down'));
const result = await vehicleService.create(validVehicle, 'user123');
expect(result.make).toBeNull(); // Graceful degradation
});
});
```
### External Service Failures
- Mock API failures to test error handling
- Test timeout scenarios
- Test network connectivity issues
- Verify graceful degradation paths