Journal / Tech Debt and Refactoring

Tech Debt and Refactoring

The Test Pyramid for SaaS: Unit, Integration, End to End

The test pyramid describes the ideal ratio of unit tests to integration tests to end to end tests in a healthy test suite. Unit tests form the base, integration tests sit in the middle, and end to end tests sit at the top. Most SaaS teams invert this unintentionally, building too many brittle end to end tests and too few integration tests. Understanding why the pyramid is shaped the way it is changes how you allocate testing effort.

What you actually need to know

  • The pyramid shape reflects cost and reliability, not importance. End to end tests are the most valuable per test. They are also the most expensive to write, run, and maintain.
  • Most teams invert the pyramid accidentally. They write lots of end to end tests early and pay for it in slow CI and brittle builds.
  • Integration tests are the most underused tier in SaaS backends. They cover the database interactions, service boundaries, and business logic combinations that unit tests miss.
  • A fast suite that runs in three minutes for every commit, plus a longer end to end suite before deploy, is a workable structure for most teams.
  • Mock at the edges. Mock external services. Do not mock your own database.
  • Coverage numbers tell you where tests exist. They do not tell you whether the tests are protecting anything important.

Test tier

Speed

Reliability

Maintenance cost

Best for

Unit

Very fast

Very high

Low

Pure logic, validators, calculators

Integration

Medium

High

Medium

Database flows, service boundaries, business logic

End to end

Slow

Lower

High

Critical user journeys, full flow smoke tests

Snapshot

Fast

Medium

Medium

Stable UI components

The core argument

The test pyramid was described by Mike Cohn in 2009 and it remains accurate. The shape is not aesthetic. It is economic. Unit tests are cheap to write and fast to run. End to end tests are expensive to write, slow to run, and break every time the UI or infrastructure shifts. If you are going to have a lot of tests, most of them should be cheap.

The practical problem I see in most SaaS codebases is not that teams ignore testing. It is that they test at the wrong tier. They write end to end tests that cover business logic, when a faster integration test would do the same job in one tenth of the time. They skip integration tests on code that is heavy on database work because writing them requires a test database setup, and that setup feels like a project.

The consequence is a suite that takes fifteen minutes to run and breaks on every UI refactor. Developers stop running it locally. CI becomes a waiting game. The suite that was supposed to build confidence starts to erode it.

The fix is deliberate tier assignment. Before writing a test, ask which tier this test belongs at. Can I test this behavior with a unit test? No, it requires database state. Can I test it with an integration test? Yes. Then write the integration test and skip the end to end test.

The three tiers in a SaaS context

Unit tests

Unit tests belong on pure logic. Validation rules, calculation engines, date utilities, permission checking functions that take an object and return a boolean. Anywhere the input is small, the output is predictable, and the function does not depend on external state.

The discipline is to extract that logic into pure functions before testing it. A permission check that requires a database call is not a unit test candidate until you refactor out the pure logic.

Integration tests

Integration tests are the most valuable tier for SaaS backends, and the most commonly underdeveloped. They cover the code that actually does the work: creating a subscription, firing a webhook, handling a failed payment, building a user's permission set from database state.

The discipline here is to use a real test database. Mocking the database in an integration test is not an integration test. It is a slow unit test. Set up a test database in CI, seed it with fixtures, and test the actual SQL. The setup cost is a few hours. The value is that you can actually trust the tests.

End to end tests

End to end tests belong on the flows that are too important to leave unverified. Sign up, log in, complete the core transaction, cancel a subscription. Five to ten flows, not fifty.

The discipline is that end to end tests are the canary, not the net. They verify that the critical paths still function after a deploy. They are not designed to catch every edge case. Edge cases belong in integration tests.

What it costs to maintain each tier

Suite configuration

Daily CI cost

Maintenance per quarter

Incident catch rate

All end to end, few unit

High, slow builds

High, brittle tests break constantly

Medium, misses edge cases

Heavy unit, few integration

Low

Low

Low, misses integration bugs

Balanced pyramid

Medium

Medium

High when calibrated correctly

Pyramid with coverage gates

Medium

Medium to high

High

The numbers here are directional, not exact. The point is that a balanced pyramid is not the lowest maintenance option. It requires ongoing discipline. But it is the highest confidence option at the lowest cost over a two or three year timeframe.

What to look for in a healthy test suite

  • A fast suite that runs in under three minutes on every commit. If it takes longer, split it.
  • A separate slow suite for validation before deploy.
  • Integration tests that use a real database, not mocks.
  • End to end tests limited to the top five or ten user flows.
  • No flaky tests in the main suite. A flaky test teaches developers to ignore failures.
  • Failure messages that name the behavior that broke, not just the assertion.
  • A documented process for skipping a test with an expiry date.
  • Coverage gates on critical modules, not blanket coverage requirements.

Expert opinion

The teams I respect most do not have the highest coverage numbers. They have the clearest sense of what their tests are protecting. They know which tests are canaries, which are nets, and which are just expensive noise. That clarity is what produces a suite that actually speeds up delivery rather than slowing it down.

Yashveer Singh, founder of Yashveer Labs

How this played out on a real project

A SaaS client I worked with had a test suite that took eighteen minutes to run. The team had invested heavily in end to end tests early on because they worked well for the MVP stage. As the product grew, the suite became a liability. Developers were disabling tests to keep CI from timing out. The coverage number looked good. The incident rate was high.

We ran a two day tech debt audit and found that the integration tier was almost empty. The billing and subscription code, heavy on database work and where most of the real bugs lived, had only end to end coverage. The pure logic functions had no tests at all.

The rebalancing took six weeks. We wrote integration tests for the billing and subscription flows first, using a real test database. Then we deleted the end to end tests that duplicated the integration coverage. The suite dropped from eighteen minutes to four. Incident rate dropped by roughly half in the two months after the change.

The companion post with a practical plan for adding tests to existing code is adding tests to a legacy codebase without going mad. On the question of whether the test suite itself has become a tech debt problem, why your test suite is slow and how to fix it is the natural one to read next.

Common mistakes

  1. Starting with end to end tests and staying there. The suite becomes slow and brittle before integration coverage exists.
  2. Mocking the database in integration tests. You are testing the mock, not the code.
  3. Setting a blanket coverage target. Coverage tells you where tests exist. It does not tell you whether they are testing the right things.
  4. Treating all flaky tests as acceptable with a retry. Flakiness is a symptom. Retrying hides it.
  5. Running the full suite on every commit. Split fast and slow suites early to keep the commit loop tight.
  6. Writing tests that test implementation rather than behavior. These tests break on every refactor and add no safety.
  7. Skipping the test database setup because it is inconvenient. A few hours of setup cost is worth less than a month of false confidence from mocked integration tests.

A six week pyramid plan

  1. Week one. Audit the current suite. Count tests by tier. Identify which tier has more tests than it needs and which is missing.
  2. Week two. Set up a test database in CI if one does not exist. Write three integration tests on the most critical data flows.
  3. Week three and four. Continue adding integration tests. One or two per working day on the modules that touch money, identity, or core product state.
  4. Week five. Review the end to end suite. Identify tests that duplicate integration coverage and remove them. Keep only the true smoke tests.
  5. Week six. Split the suite into fast and slow. Fast suite on every commit. Slow suite before deploy. Measure the commit loop time and target under three minutes.

For the broader discipline of managing the test investment as a team, the tech debt ledger post covers how to track the test gaps the same way you track other technical liabilities.

FAQ

Frequently asked

  • What is the correct ratio of unit to integration to end to end tests for a SaaS product?
  • Why do most SaaS teams end up with too many end to end tests?
  • What should integration tests cover in a SaaS backend?
  • When is a unit test the right choice versus an integration test?
  • How do I handle slow end to end tests without removing them?
  • What is the test trophy and how does it differ from the test pyramid?
  • Should SaaS teams use snapshot tests and what are the risks?

Author

Why you should hire Yashveer Singh for this

The kind of work this article describes is the kind of work I do every week. Production deployments, scaling decisions, the architecture choices that compound over years. I am Yashveer Singh, founder of Yashveer Labs. If you need this done, I do not need to be sold on the brief. Send me what you have and I will tell you what it actually takes.

Start the conversation See the work DM on Instagram