The Test Pyramid describes the relative distribution of automated tests across different scopes. Its broad base contains unit tests that check small pieces of behavior in isolation. The middle contains integration tests that verify interactions between components or external systems. Its narrow top contains end-to-end tests that exercise complete user or business workflows. Layer names vary, but the central principle remains the same: establish most confidence with inexpensive, focused tests and add broader tests where they provide distinct evidence.
In a CI/CD pipeline, fast unit tests should normally run on each proposed change or commit, before expensive deployment activities. For example, an order-processing application can test pricing rules, input validation, and retry decisions without provisioning a database or invoking a payment provider. These tests should be deterministic and return actionable failures quickly. Configure test commands to return a failing exit status when assertions fail so that the pipeline blocks promotion rather than merely recording a report.
Integration tests verify behavior that isolated tests cannot establish. After producing a deployable artifact, a pipeline might deploy it into an isolated test environment and check database queries, queue processing, API contracts, and access permissions. A cloud function can pass every unit test yet fail when its execution role lacks permission to read a queue. Tests against real cloud resources help expose configuration and service-interaction defects that mocks and local emulators may miss.
End-to-end tests should cover a carefully selected set of important workflows, such as placing an order and observing its fulfillment status. They usually run after deployment to a representative staging environment because they require multiple working components. Browser automation is one option, but an end-to-end test can also exercise an API-driven workflow. Run these tests against the same immutable artifact intended for production rather than rebuilding a different artifact after testing.
Test placement should reflect cost, risk, and feedback needs rather than a rigid schedule. Run quick integration or contract tests early when practical, and consider executing long-running performance suites on release candidates or scheduled pipelines. Security checks also belong at appropriate stages: source and dependency checks can run early, while dynamic security testing needs a running application. Performance and security describe testing objectives, not fixed levels of the pyramid.
The pyramid does not prescribe a universal percentage for each test type, and more unit tests do not automatically mean better coverage. Excessive mocking can validate assumptions rather than actual behavior, while excessive end-to-end testing produces slow feedback and failures that are difficult to diagnose. Integration-heavy systems may reasonably need a larger middle layer. Choose the smallest test scope that can reliably detect each important failure mode.
Cloud test environments introduce resource costs, provisioning delays, eventual consistency, and cleanup requirements. Use infrastructure as code, isolated test data, least-privilege test roles, and bounded polling for asynchronous outcomes. Repair flaky tests instead of masking them with unlimited retries. After deployment, use targeted smoke tests and operational health checks to confirm basic functionality; these complement preproduction testing rather than replace it.