7.8 KiB
name, description
| name | description |
|---|---|
| test-automation-architecture | Use when organizing test suites, setting up CI/CD testing pipelines, choosing test levels (unit vs integration vs E2E), fixing slow CI feedback, or migrating from inverted test pyramid - provides test pyramid guidance and anti-patterns |
Test Automation Architecture
Overview
Core principle: Test pyramid - many fast unit tests, fewer integration tests, fewest E2E tests.
Target distribution: 70% unit, 20% integration, 10% E2E
Flexibility: Ratios can vary based on constraints (e.g., 80/15/5 if E2E infrastructure is expensive, 60/30/10 for microservices). Key is maintaining pyramid shape - more unit than integration than E2E.
Starting from zero tests: Don't try to reach target distribution immediately. Start with unit tests only (Phase 1), add integration (Phase 2), add E2E last (Phase 3). Distribute organically over 6-12 months.
Test Pyramid Quick Reference
| Test Level | Purpose | Speed | When to Use |
|---|---|---|---|
| Unit | Test individual functions/methods in isolation | Milliseconds | Business logic, utilities, calculations, error handling |
| Integration | Test components working together | Seconds | API contracts, database operations, service interactions |
| E2E | Test full user workflows through UI | Minutes | Critical user journeys, revenue flows, compliance paths |
Rule: If you can test it at a lower level, do that instead.
Test Level Selection Guide
| What You're Testing | Test Level | Why |
|---|---|---|
| Function returns correct value | Unit | No external dependencies |
| API endpoint response format | Integration | Tests API contract, not full workflow |
| Database query performance | Integration | Tests DB interaction, not UI |
| User signup → payment flow | E2E | Crosses multiple systems, critical revenue |
| Form validation logic | Unit | Pure function, no UI needed |
| Service A calls Service B correctly | Integration | Tests contract, not user workflow |
| Button click updates state | Unit | Component behavior, no backend |
| Multi-step checkout process | E2E | Critical user journey, revenue impact |
Guideline: Unit tests verify "did I build it right?", E2E tests verify "did I build the right thing?"
Anti-Patterns Catalog
❌ Inverted Pyramid
Symptom: 500 E2E tests, 100 unit tests
Why bad: Slow CI (30min+), brittle tests, hard to debug, expensive maintenance
Fix: Migrate 70% of E2E tests down to unit/integration. Use Migration Strategy below.
❌ All Tests on Every Commit
Symptom: Running full 30-minute test suite on every PR
Why bad: Slow feedback kills productivity, wastes CI resources
Fix: Progressive testing - unit tests on PR, integration on merge, E2E nightly/weekly
❌ No Test Categorization
Symptom: All tests in one folder, one command, one 30-minute run
Why bad: Can't run subsets, no fail-fast, poor organization
Fix: Separate by level (unit/, integration/, e2e/) with independent configs
❌ Slow CI Feedback Loop
Symptom: Waiting 20+ minutes for test results on every commit
Why bad: Context switching, delayed bug detection, reduced productivity
Fix: Fail fast - run fastest tests first, parallelize, cache dependencies
❌ No Fail Fast
Symptom: Running all 500 tests even after first test fails
Why bad: Wastes CI time, delays feedback
Fix: Configure test runner to stop on first failure in CI (not locally)
CI/CD Pipeline Patterns
| Event | Run These Tests | Duration Target | Why |
|---|---|---|---|
| Every Commit (Pre-Push) | Lint + unit tests | < 5 min | Fast local feedback |
| Pull Request | Lint + unit + integration | < 15 min | Gate before merge, balance speed/coverage |
| Merge to Main | All tests (unit + integration + E2E) | < 30 min | Full validation before deployment |
| Nightly/Scheduled | Full suite + performance tests | < 60 min | Catch regressions, performance drift |
| Pre-Deployment | Smoke tests only (5-10 critical E2E) | < 5 min | Fast production validation |
Progressive complexity: Start with just unit tests on PR, add integration after mastering that, add E2E last.
Folder Structure Patterns
Basic (Small Projects)
tests/
├── unit/
├── integration/
└── e2e/
Mirrored (Medium Projects)
src/
├── components/
├── services/
└── utils/
tests/
├── unit/
│ ├── components/
│ ├── services/
│ └── utils/
├── integration/
└── e2e/
Feature-Based (Large Projects)
features/
├── auth/
│ ├── src/
│ └── tests/
│ ├── unit/
│ ├── integration/
│ └── e2e/
└── payment/
├── src/
└── tests/
Choose based on: Team size (<5: Basic, 5-20: Mirrored, 20+: Feature-Based)
Migration Strategy (Fixing Inverted Pyramid)
If you have 500 E2E tests and 100 unit tests:
Week 1-2: Audit
- Categorize each E2E test: Critical (keep) vs Redundant (migrate)
- Identify 10-20 critical user journeys
- Target: Keep 50-100 E2E tests maximum
Week 3-4: Move High-Value Tests Down
- Convert 200 E2E tests → integration tests (test API/services without UI)
- Convert 100 E2E tests → unit tests (pure logic tests)
- Delete 100 truly redundant E2E tests
Week 5-6: Build Unit Test Coverage
- Add 200-300 unit tests for untested business logic
- Target: 400+ unit tests total
Week 7-8: Reorganize
- Split tests into folders (unit/, integration/, e2e/)
- Create separate test configs
- Update CI to run progressively
Expected result: 400 unit, 200 integration, 100 E2E (~70/20/10 distribution)
Your First CI Pipeline
Start simple, add complexity progressively:
Phase 1 (Week 1): Unit tests only
on: [pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- run: npm run test:unit
Phase 2 (Week 2-3): Add lint + integration
jobs:
lint:
runs-on: ubuntu-latest
steps:
- run: npm run lint
test:
needs: lint
runs-on: ubuntu-latest
steps:
- run: npm run test:unit
- run: npm run test:integration
Phase 3 (Week 4+): Add E2E on main branch
jobs:
e2e:
if: github.ref == 'refs/heads/main'
needs: [lint, test]
runs-on: ubuntu-latest
steps:
- run: npm run test:e2e
Don't start with full complexity - master each phase before adding next.
Common Mistakes
❌ Testing Everything at E2E Level
Fix: Use Test Level Selection Guide above. Most tests belong at unit level.
❌ No Parallel Execution
Symptom: Tests run sequentially, taking 30min when they could run in 10min
Fix: Run independent test suites in parallel (unit + lint simultaneously)
❌ No Caching
Symptom: Re-downloading dependencies on every CI run (5min wasted)
Fix: Cache node_modules, .m2, .gradle based on lock file hash
Quick Reference
Test Distribution Target:
- 70% unit tests (fast, isolated)
- 20% integration tests (component interaction)
- 10% E2E tests (critical user journeys)
CI Pipeline Events:
- PR: unit + integration (< 15min)
- Main: all tests (< 30min)
- Deploy: smoke tests only (< 5min)
Folder Organization:
- Small team: tests/unit, tests/integration, tests/e2e
- Large team: feature-based with embedded test folders
Migration Path:
- Audit E2E tests
- Move 70% down to unit/integration
- Add missing unit tests
- Reorganize folders
- Update CI pipeline
Bottom Line
Many fast tests beat few slow tests.
Test pyramid exists because it balances confidence (E2E) with speed (unit). Organize tests by level, run progressively in CI, fail fast.