// Comprehensive test strategy guidance including test pyramid design, coverage goals, test categorization, CI/CD integration, and risk-based prioritization. Use when planning testing approaches, setting up test infrastructure, or optimizing test suites. Trigger keywords: test strategy, test pyramid, coverage goals, what to test, test organization, CI/CD testing, test prioritization, testing approach.
| name | test-strategy |
| description | Comprehensive test strategy guidance including test pyramid design, coverage goals, test categorization, CI/CD integration, and risk-based prioritization. Use when planning testing approaches, setting up test infrastructure, or optimizing test suites. Trigger keywords: test strategy, test pyramid, coverage goals, what to test, test organization, CI/CD testing, test prioritization, testing approach. |
Test strategy defines how to approach testing for a project, balancing thoroughness with efficiency. A well-designed strategy ensures critical functionality is covered while avoiding over-testing trivial code. This skill covers the test pyramid, coverage metrics, test categorization, and integration with CI/CD pipelines.
Structure tests in layers with appropriate ratios:
/\
/ \ E2E Tests (5-10%)
/----\ - Critical user journeys
/ \ - Cross-system integration
/--------\ Integration Tests (15-25%)
/ \ - API contracts
/------------\ - Database interactions
/ \ - Service boundaries
/----------------\ Unit Tests (65-80%)
- Business logic
- Pure functions
- Edge cases
Recommended Ratios:
Coverage Targets by Component Type:
| Component Type | Line Coverage | Branch Coverage | Notes |
|---|---|---|---|
| Business Logic | 90%+ | 85%+ | Critical paths fully covered |
| API Handlers | 80%+ | 75%+ | All endpoints tested |
| Utilities | 95%+ | 90%+ | Pure functions easily testable |
| UI Components | 70%+ | 60%+ | Focus on behavior over markup |
| Infrastructure | 60%+ | 50%+ | Integration tests preferred |
Coverage Anti-patterns to Avoid:
Always Test:
Consider Not Testing:
Test Smell Detection:
// BAD: Testing trivial code
test("getter returns value", () => {
const user = new User("John");
expect(user.getName()).toBe("John");
});
// GOOD: Testing meaningful behavior
test("user cannot change name to empty string", () => {
const user = new User("John");
expect(() => user.setName("")).toThrow(ValidationError);
});
Directory Structure:
tests/
โโโ unit/
โ โโโ services/
โ โโโ models/
โ โโโ utils/
โโโ integration/
โ โโโ api/
โ โโโ database/
โ โโโ external-services/
โโโ e2e/
โ โโโ flows/
โ โโโ pages/
โโโ fixtures/
โ โโโ factories/
โ โโโ mocks/
โโโ helpers/
โโโ setup.ts
โโโ assertions.ts
Test Tagging System:
// Jest example with tags
describe("[unit][fast] UserService", () => {});
describe("[integration][slow] DatabaseRepository", () => {});
describe("[e2e][critical] CheckoutFlow", () => {});
// Run specific categories
// npm test -- --grep="\[unit\]"
// npm test -- --grep="\[critical\]"
Naming Conventions:
[ComponentName].[scenario].[expected_result].test.ts
Examples:
UserService.createUser.returnsNewUser.test.ts
PaymentProcessor.invalidCard.throwsPaymentError.test.ts
Pipeline Stage Configuration:
# .github/workflows/test.yml
name: Test Pipeline
on: [push, pull_request]
jobs:
unit-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run Unit Tests
run: npm test -- --grep="\[unit\]" --coverage
- name: Upload Coverage
uses: codecov/codecov-action@v3
integration-tests:
runs-on: ubuntu-latest
needs: unit-tests
services:
postgres:
image: postgres:15
env:
POSTGRES_PASSWORD: test
steps:
- uses: actions/checkout@v4
- name: Run Integration Tests
run: npm test -- --grep="\[integration\]"
e2e-tests:
runs-on: ubuntu-latest
needs: integration-tests
steps:
- uses: actions/checkout@v4
- name: Run E2E Tests
run: npm run test:e2e
CI Test Optimization:
Risk Matrix for Prioritization:
| Impact โ / Likelihood โ | Low | Medium | High |
|---|---|---|---|
| High | Medium Priority | High Priority | Critical |
| Medium | Low Priority | Medium Priority | High Priority |
| Low | Skip/Manual | Low Priority | Medium Priority |
Risk Factors to Consider:
Prioritized Test Categories:
Critical (P0): Run on every commit
High (P1): Run on PR merge
Medium (P2): Run nightly
Low (P3): Run weekly
Test Behavior, Not Implementation
Keep Tests Independent
Use Test Doubles Appropriately
Maintain Test Quality
Fast Feedback Loop
Document Test Intent
# Feature: User Registration
## Risk Assessment
- Business Impact: HIGH (user acquisition)
- Complexity: MEDIUM (email validation, password rules)
- Change Frequency: LOW (stable feature)
## Test Coverage Plan
### Unit Tests (P0)
- [ ] Email format validation
- [ ] Password strength requirements
- [ ] Username uniqueness check logic
- [ ] Profile data sanitization
### Integration Tests (P1)
- [ ] Database user creation
- [ ] Email service integration
- [ ] Duplicate email handling
### E2E Tests (P0)
- [ ] Happy path: complete registration flow
- [ ] Error path: duplicate email shows error
## Coverage Targets
- Line coverage: 85%
- Branch coverage: 80%
- Critical paths: 100%
// jest.config.js
module.exports = {
projects: [
{
displayName: "unit",
testMatch: ["<rootDir>/tests/unit/**/*.test.ts"],
setupFilesAfterEnv: ["<rootDir>/tests/helpers/unit-setup.ts"],
},
{
displayName: "integration",
testMatch: ["<rootDir>/tests/integration/**/*.test.ts"],
setupFilesAfterEnv: ["<rootDir>/tests/helpers/integration-setup.ts"],
globalSetup: "<rootDir>/tests/helpers/db-setup.ts",
globalTeardown: "<rootDir>/tests/helpers/db-teardown.ts",
},
],
coverageThreshold: {
global: {
branches: 75,
functions: 80,
lines: 80,
statements: 80,
},
"./src/services/": {
branches: 90,
lines: 90,
},
},
};
// scripts/select-tests.ts
interface TestFile {
path: string;
priority: "P0" | "P1" | "P2" | "P3";
tags: string[];
}
function selectTestsForPipeline(
context: "commit" | "pr" | "nightly" | "weekly",
): TestFile[] {
const allTests = getTestManifest();
const priorityMap = {
commit: ["P0"],
pr: ["P0", "P1"],
nightly: ["P0", "P1", "P2"],
weekly: ["P0", "P1", "P2", "P3"],
};
return allTests.filter((test) =>
priorityMap[context].includes(test.priority),
);
}