Testing Strategy Workflow¶
Purpose: Plan and achieve test coverage targets (>80% business logic, >60% overall) through systematic test analysis and prioritization.
When to Use¶
| Trigger | Description |
|---|---|
| Post-COMPLEX Feature | After implementing major features |
| Coverage Drop | When coverage falls below thresholds |
| Test Debt Sprint | Dedicated testing improvement effort |
| New Project | Establishing testing foundation |
| Pre-Release | Ensuring quality before deployment |
Coverage Targets¶
| Category | Target | Warning | Critical |
|---|---|---|---|
| Business Logic | >80% | 70-80% | <70% |
| Overall | >60% | 50-60% | <50% |
| Critical Paths | >90% | 80-90% | <80% |
Prerequisites¶
Before starting:
- Test framework configured
- Coverage tool available
- CI/CD running tests
- Access to current coverage report
- Understanding of business-critical features
Strategy Process¶
Phase 1: Coverage Analysis
↓
Phase 2: Critical Path Identification
↓
Phase 3: Test Pyramid Planning
↓
Phase 4: Test Prioritization
↓
Phase 5: Edge Case Planning
↓
Phase 6: Flaky Test Remediation
↓
Phase 7: Implementation Roadmap
Phase 1: Coverage Analysis¶
1.1 Generate Coverage Report¶
Node.js (Jest/Vitest):
Python (pytest):
Go:
Rust:
1.2 Analyze Coverage Gaps¶
Review coverage report for:
| Area | Target | Current | Gap |
|---|---|---|---|
src/auth/ | 90% | 45% | -45% |
src/api/ | 80% | 62% | -18% |
src/utils/ | 60% | 78% | +18% |
| Overall | 60% | 55% | -5% |
1.3 Identify Uncovered Files¶
List files with lowest coverage:
Lowest Coverage Files:
1. src/auth/oauth.ts - 12% (critical!)
2. src/api/payments.ts - 28% (critical!)
3. src/services/email.ts - 35%
4. src/utils/validation.ts - 42%
5. src/api/users.ts - 48%
Phase 2: Critical Path Identification¶
2.1 Define Critical Paths¶
Critical paths are user journeys that MUST work:
| Path | Description | Files | Priority |
|---|---|---|---|
| Authentication | Login, logout, session | auth/* | P0 |
| Checkout | Cart → Payment → Confirm | payments/, cart/ | P0 |
| Registration | Signup → Verify → Profile | users/, email/ | P1 |
| Search | Query → Results → Filter | search/, api/ | P1 |
2.2 Map Critical Files¶
For each critical path, list involved files:
Authentication Path:
src/auth/login.ts - 45% coverage
src/auth/session.ts - 52% coverage
src/auth/middleware.ts - 88% coverage
src/models/user.ts - 72% coverage
2.3 Calculate Critical Path Coverage¶
Authentication Path:
- Total lines: 450
- Covered lines: 267
- Coverage: 59% (target: 90%)
- Gap: 183 lines to cover
Phase 3: Test Pyramid Planning¶
3.1 Ideal Test Pyramid¶
/\
/ \
/ E2E \ 10% - Slow, expensive, covers user flows
/______\
/ \
/Integration\ 20% - Medium speed, covers integrations
/______________\
/ \
/ Unit Tests \ 70% - Fast, cheap, covers logic
/____________________\
3.2 Current Distribution¶
Analyze current test distribution:
Current State:
- Unit tests: 45 (60%)
- Integration: 25 (33%)
- E2E: 5 (7%)
Ideal State:
- Unit tests: 70 (70%)
- Integration: 20 (20%)
- E2E: 10 (10%)
Gap:
- Need +25 unit tests
- Need -5 integration tests (or OK)
- Need +5 E2E tests
3.3 Test Type Guidelines¶
Unit Tests (70%): - Pure functions - Business logic - Utility functions - Model methods - State transitions
Integration Tests (20%): - API endpoints - Database operations - Service interactions - Authentication flows - External service mocks
E2E Tests (10%): - Critical user journeys - Happy path scenarios - Cross-system flows - Smoke tests
Phase 4: Test Prioritization¶
4.1 Priority Matrix¶
| Priority | Criteria | Example |
|---|---|---|
| P0 | Critical path, no tests | Payment processing |
| P1 | Critical path, low coverage | Authentication |
| P2 | High risk, medium coverage | Data validation |
| P3 | Medium risk, any coverage | Utility functions |
| P4 | Low risk, nice to have | Formatting helpers |
4.2 Effort Estimation¶
| Test Type | Effort | Coverage Impact |
|---|---|---|
| Unit (simple) | 15 min | High |
| Unit (complex) | 1 hour | High |
| Integration | 2 hours | Medium |
| E2E | 4 hours | Low (but valuable) |
4.3 Prioritized Test Backlog¶
## Test Backlog
### P0 - Immediate (This Sprint)
- [ ] Unit: payment.processPayment()
- [ ] Unit: auth.validateToken()
- [ ] Integration: POST /api/payments
- [ ] E2E: Complete checkout flow
### P1 - High (Next Sprint)
- [ ] Unit: auth.refreshToken()
- [ ] Unit: user.validateEmail()
- [ ] Integration: GET /api/users/:id
- [ ] E2E: Registration flow
### P2 - Medium (Backlog)
- [ ] Unit: validation helpers
- [ ] Unit: formatting utilities
- [ ] Integration: Search API
### P3 - Low (Nice to Have)
- [ ] Unit: logging utilities
- [ ] Unit: config loaders
Phase 5: Edge Case Planning¶
5.1 Required Edge Cases¶
Every function should test:
| Category | Cases | Example |
|---|---|---|
| Null/Undefined | null, undefined input | validateUser(null) |
| Empty | "", [], {} | searchUsers("") |
| Boundary | 0, -1, MAX_INT | setQuantity(0) |
| Invalid Type | Wrong type input | calculatePrice("abc") |
| Concurrent | Race conditions | Parallel updates |
5.2 Edge Case Template¶
describe('validateUser', () => {
// Happy path
it('should validate correct user data', () => {
// ...
});
// Null/Undefined
it('should reject null input', () => {
expect(() => validateUser(null)).toThrow('Invalid input');
});
it('should reject undefined input', () => {
expect(() => validateUser(undefined)).toThrow('Invalid input');
});
// Empty
it('should reject empty object', () => {
expect(() => validateUser({})).toThrow('Missing required fields');
});
// Boundary
it('should reject username under minimum length', () => {
expect(() => validateUser({ username: 'ab' })).toThrow('Username too short');
});
it('should reject username over maximum length', () => {
const longUsername = 'a'.repeat(51);
expect(() => validateUser({ username: longUsername })).toThrow('Username too long');
});
// Invalid type
it('should reject non-object input', () => {
expect(() => validateUser('string')).toThrow('Invalid input type');
});
});
5.3 Edge Case Checklist¶
For each function:
- Happy path tested
- Null input tested
- Undefined input tested
- Empty input tested
- Minimum boundary tested
- Maximum boundary tested
- Invalid type tested
- Error conditions tested
Phase 6: Flaky Test Remediation¶
6.1 Identify Flaky Tests¶
Signs of flaky tests: - Intermittent failures in CI - Tests that pass locally but fail in CI - Tests that depend on execution order - Tests with timing-dependent assertions
6.2 Common Causes & Fixes¶
| Cause | Symptom | Fix |
|---|---|---|
| Timing | Random timeouts | Use proper async/await |
| Order dependency | Fails when run alone | Reset state in beforeEach |
| Shared state | Random failures | Isolate test data |
| External services | Network failures | Mock external calls |
| Date/time | Fails at midnight | Mock dates |
6.3 Flaky Test Patterns¶
Bad: Timing-dependent
// FLAKY
it('should update after delay', () => {
triggerUpdate();
setTimeout(() => {
expect(state.updated).toBe(true);
}, 100);
});
Good: Proper async
// STABLE
it('should update after delay', async () => {
await triggerUpdate();
expect(state.updated).toBe(true);
});
Bad: Shared state
// FLAKY
let counter = 0;
it('should increment', () => {
counter++;
expect(counter).toBe(1);
});
it('should be one', () => {
expect(counter).toBe(1); // Depends on previous test
});
Good: Isolated
// STABLE
describe('counter', () => {
let counter;
beforeEach(() => {
counter = 0;
});
it('should increment', () => {
counter++;
expect(counter).toBe(1);
});
});
Phase 7: Implementation Roadmap¶
7.1 Sprint Planning¶
## Sprint 1: Critical Path (2 weeks)
### Goals
- Achieve 90% coverage on authentication
- Achieve 90% coverage on payments
- Add 5 E2E tests for critical paths
### Tasks
1. Unit tests for auth module (20 tests)
2. Unit tests for payment module (15 tests)
3. Integration tests for auth API (5 tests)
4. E2E test: Complete checkout (1 test)
5. E2E test: Login flow (1 test)
### Expected Outcome
- Overall coverage: 55% → 65%
- Critical path coverage: 59% → 90%
7.2 Test Writing Guidelines¶
Test Structure:
describe('Module or Function', () => {
// Setup
beforeEach(() => {
// Reset state
});
describe('method or scenario', () => {
it('should [expected behavior] when [condition]', () => {
// Arrange
const input = createTestInput();
// Act
const result = functionUnderTest(input);
// Assert
expect(result).toEqual(expectedOutput);
});
});
});
Naming Convention:
should [expected behavior] when [condition]
Examples:
- should return user when valid ID provided
- should throw error when user not found
- should update timestamp when saving
7.3 Coverage Tracking¶
Track coverage weekly:
| Week | Overall | Business | Critical | Tests Added |
|---|---|---|---|---|
| 1 | 55% | 62% | 59% | +15 |
| 2 | 62% | 75% | 78% | +22 |
| 3 | 68% | 82% | 88% | +18 |
| 4 | 72% | 85% | 92% | +12 |
Quick Reference¶
Coverage Commands¶
# Node.js
npm test -- --coverage --coverageReporters=text-summary
# Python
pytest --cov=src --cov-report=term-missing
# Go
go test -cover ./... | grep -E "coverage:"
# Rust
cargo tarpaulin --out Stdout
Test Templates¶
Unit Test:
describe('functionName', () => {
it('should [behavior] when [condition]', () => {
const result = functionName(input);
expect(result).toEqual(expected);
});
});
Integration Test:
describe('POST /api/resource', () => {
it('should create resource when valid data', async () => {
const response = await request(app)
.post('/api/resource')
.send(validData);
expect(response.status).toBe(201);
});
});
Checklist¶
Analysis¶
- Coverage report generated
- Gaps identified
- Critical paths mapped
- Current pyramid analyzed
Planning¶
- Tests prioritized
- Edge cases documented
- Flaky tests identified
- Sprint plan created
Implementation¶
- P0 tests written
- P1 tests written
- Edge cases covered
- Flaky tests fixed
Validation¶
- Coverage targets met
- All tests passing
- No flaky tests
- CI/CD updated
Related Workflows¶
- code-review.md - Includes test validation
- refactoring.md - Tests enable safe refactoring
- troubleshooting.md - When tests fail unexpectedly