The Testing Pyramid: Wrapping Up with CI/CD and Best Practices - Part 5
Software testing is more than writing a few unit tests and hoping for the best. To deliver reliable software, teams need a balanced testing strategy — one that combines Unit, Integration, and End-to-End (E2E) tests in the right proportions. This is where the Testing Pyramid comes in.
In this final part of our testing series, we’ll:
- Understand the Testing Pyramid model.
- Explore how to balance different types of tests.
- Learn how to integrate testing into CI/CD pipelines.
- Review best practices for building a sustainable testing culture.
The Testing Pyramid Explained
The Testing Pyramid (popularized by Mike Cohn) is a metaphor for structuring automated tests:
1
2
3
4
5
6
7
▲
| End-to-End (fewest, slowest)
|
| Integration (moderate amount, balanced)
|
| Unit Tests (largest base, fastest)
▼
1. Unit Tests (Foundation)
- Fast, cheap, and precise.
- Cover small pieces of logic in isolation.
- Should make up 60–70% of your automated test suite.
Example: Testing a function that calculates interest rates.
2. Integration Tests (Middle Layer)
- Validate how components interact.
- Cover database queries, API requests, or service orchestration.
- Should make up 20–30% of your test suite.
Example: Ensuring your API endpoint correctly fetches data from the database and formats the response.
3. End-to-End Tests (Top)
- Simulate real user flows across the full stack.
- Catch bugs unit or integration tests can’t.
- Should make up 10–15% of your suite (because they’re slow and expensive).
Example: A test where a user logs in, adds a product to their cart, and completes checkout.
Integrating Tests into CI/CD Pipelines
Automated tests are only valuable if they’re run consistently. Modern software teams embed them into CI/CD pipelines.
Step 1: Run Unit Tests Early
- Execute on every commit or pull request.
- Fail fast: block merges if unit tests fail.
Step 2: Run Integration Tests on Build/Deploy
- Run after the app compiles successfully.
- Can use a containerized test environment with mock or staging databases.
Step 3: Run End-to-End Tests on Staging
- Triggered before production deployment.
- Some teams run smoke E2E tests in production (carefully) to ensure critical flows still work.
Example CI/CD Flow (GitHub Actions / GitLab / Jenkins):
1
2
3
4
5
6
7
8
9
10
11
12
13
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Install dependencies
run: npm install
- name: Run unit tests
run: npm test -- --unit
- name: Run integration tests
run: npm test -- --integration
- name: Run e2e tests
run: npm run test:e2e
Best Practices for a Balanced Testing Strategy
1. Follow the Pyramid, Not the Ice Cream Cone
- Too many E2E tests = slow, brittle pipeline.
- Too few unit tests = shaky foundation.
- Balance is key.
2. Use Test Doubles Wisely
- Mocks/Stubs in unit tests to isolate dependencies.
- Minimal mocking in integration tests — rely on real services where possible.
3. Make Tests Deterministic
- Tests should always produce the same result.
- Avoid flaky tests (caused by race conditions, timeouts, or external dependencies).
4. Keep Tests Fast
- Aim for seconds, not minutes.
- Developers won’t run slow tests locally.
5. Automate Everything in CI/CD
- Manual testing has its place, but regression checks must be automated.
- CI/CD pipelines should be your safety net before production.
6. Monitor and Improve Test Coverage
- Coverage isn’t everything, but low coverage usually indicates gaps.
- Focus on critical paths rather than chasing 100%.
7. Treat Tests as Code
- Tests should be maintainable, reviewed, and refactored like production code.
- Avoid “test rot” where tests become outdated or ignored.
Final Thoughts
The journey from unit → integration → E2E tests gives you confidence at every level of your system.
- Unit tests keep your building blocks solid.
- Integration tests ensure the blocks fit together.
- E2E tests confirm the entire structure works as intended.
By following the Testing Pyramid, integrating tests into CI/CD pipelines, and practicing discipline in writing effective tests, you’ll achieve:
- Faster feedback loops.
- Fewer production bugs.
- Higher developer confidence.
- Happier end-users.
Testing isn’t just about catching bugs, it’s about building trustworthy software at scale.
Next Steps for You:
- Audit your current test suite.
- See if you’re over-relying on one type of test.
- Gradually reshape your suite into a pyramid, not an ice cream cone.