-
Notifications
You must be signed in to change notification settings - Fork 0
Testing Pyramid
The Testing Pyramid is a conceptual framework that helps teams understand the ideal distribution of test types in an automated test suite. It was originally proposed by Mike Cohn in his book "Succeeding with Agile".
/\
/ \ UI/E2E Tests (Few)
/----\
/ \ Integration Tests (More)
/--------\
\ / Unit Tests (Most)
\______/
The testing pyramid suggests that you should have:
- Many unit tests at the base of the pyramid
- Some integration tests in the middle
- Few end-to-end tests at the top
This distribution optimizes for:
- Speed: Unit tests are faster to execute than integration or E2E tests
- Stability: Lower-level tests are less prone to flakiness
- Cost: Maintaining large numbers of E2E tests is expensive
- Coverage: The combination provides comprehensive coverage
Unit tests verify that individual units of code (functions, methods, classes) work correctly in isolation.
Characteristics:
- Fast: Execute in milliseconds
- Isolated: No external dependencies (databases, APIs, etc.)
- Numerous: Should comprise around 70-80% of your test suite
- Focused: Test a single unit of functionality
Examples:
// Example Jest unit test
test('calculateTotal adds tax correctly', () => {
expect(calculateTotal(100, 0.1)).toBe(110);
});Integration tests verify that different units of code work together correctly.
Characteristics:
- Moderate speed: Execute in seconds
- Some dependencies: Test interactions between components
- Moderate number: Should comprise around 15-20% of your test suite
- Broader scope: Test multiple units working together
Examples:
// Example integration test
test('user service saves to database correctly', async () => {
const user = { name: 'Test User', email: 'test@example.com' };
await userService.create(user);
const savedUser = await db.findUserByEmail('test@example.com');
expect(savedUser.name).toBe('Test User');
});End-to-end tests verify the entire system works correctly from a user's perspective.
Characteristics:
- Slower: Execute in seconds or minutes
- Full dependencies: Test the entire system
- Fewer tests: Should comprise around 5-10% of your test suite
- User-focused: Test user journeys and flows
Examples:
// Example Cypress E2E test
it('user can log in and view dashboard', () => {
cy.visit('/login');
cy.get('#email').type('user@example.com');
cy.get('#password').type('password123');
cy.get('#login-button').click();
cy.url().should('include', '/dashboard');
cy.get('h1').should('contain', 'Welcome');
});When the pyramid is inverted (many E2E tests, few unit tests), it's called an "ice cream cone":
____
/ \
/ \ Unit Tests (Few)
/--------\
/ \ Integration Tests (Some)
\__________/ E2E Tests (Many)
This leads to:
- Slow test suites
- Brittle tests
- High maintenance costs
- Difficulty in identifying root causes of failures
When there are many unit tests and E2E tests but few integration tests:
/\
/ \ E2E Tests (Many)
/____\
\ / Integration Tests (Few)
\ /
\/ Unit Tests (Many)
This leads to:
- An integration gap
- Tests that pass in isolation but fail in real usage
- Missing critical component interaction testing
- Start with unit tests: Build a solid foundation
- Add integration tests: Focus on critical component interactions
- Finish with E2E tests: Cover key user journeys
- Monitor test distribution: Regularly check your test distribution
- Balance test types: Adjust based on project needs and stability
Different applications may require different distributions:
- Frontend-heavy applications: May need more component tests
- API/backend services: May need more integration tests
- Critical systems: May warrant more E2E coverage in critical paths
- Microservices: May need more contract tests between services
- JavaScript: Jest, Mocha, Jasmine
- Python: pytest, unittest
- Java: JUnit, TestNG
- C#: NUnit, xUnit.net
- API: Postman, REST Assured, Supertest
- Database: TestContainers, DBUnit
- Component: React Testing Library, Vue Test Utils
- Web: Cypress, Playwright, Selenium
- Mobile: Appium, Detox, Espresso
- API: Postman, Karate DSL
- Cohn, M. (2009). Succeeding with Agile: Software Development Using Scrum.
- Fowler, M. "TestPyramid" - https://martinfowler.com/bliki/TestPyramid.html
- "The Practical Test Pyramid" - https://martinfowler.com/articles/practical-test-pyramid.html