Q28 of 37 · API testing

How do you decide what to cover at the API layer vs the UI layer to avoid duplication?

API testingSeniorapitest-pyramidui-testingstrategysenior

Short answer

Short answer: Cover business logic, validation, auth, and edge cases at the API layer (fast, deterministic). Cover only UI-specific concerns at the UI layer: rendering, conditional UI, accessibility, the golden-path user journey. If a behaviour can be tested either way, prefer API.

Detail

Every team eventually has overlapping coverage — the same flow tested at three layers. The right split saves time without losing coverage.

The principle: each layer tests what only it can test. Lower layers test logic; UI tests render and interaction.

At the API layer (most coverage):

  • Business logic: "discount applies when total > £50."
  • Validation: required fields, format checks, ranges.
  • Auth & permissions: who can do what, scope enforcement.
  • Edge cases: null handling, empty arrays, very long strings.
  • Error paths: 400/401/403/404/500 conditions.
  • Schema integrity.
  • Rate limits, idempotency keys, async job lifecycle.

At the UI layer (selective):

  • The golden-path user journey: signup → buy → confirmation.
  • Conditional rendering (does the right component show?).
  • Form behaviour (disabled until valid, error display).
  • Accessibility — keyboard nav, screen-reader hooks, focus management.
  • UI state machines that aren't reflected in API state — modals, drawers, toasts.
  • Visual regression for critical screens (sparingly).

What does not belong at the UI layer:

  • "Wrong password shows error" — covered by API + a single UI test that asserts the display of an error, not the auth logic.
  • "Validation rejects invalid email" — API tests cover the logic; UI test covers that the error appears at all.
  • "Admins see admin menu, viewers don't" — auth covered at API; UI test covers conditional render of the menu.

The duplication trap:

A common pattern: a UI test for "user can update name" walks through login, navigation, form fill, save — 30 seconds. The same coverage at the API layer takes 50ms. The UI test still exists "for confidence." This is the leak.

The fix: for every UI test, ask:

  1. What does this verify that an API test can't?
  2. If "rendering," "interaction," or "user journey" — keep it.
  3. If "logic," "validation," or "error message text" — move to API.

Numerically:

  • API tests: hundreds to thousands. Aim for 80-90% endpoint × scenario coverage.
  • UI tests: dozens to ~100. Tightly focused on user journeys and rendering.

Tooling: same framework where possible. Playwright covers both via APIRequestContext + browser context. Cypress also covers both with cy.request. Sharing the runner means shared CI, shared reports, and shared fixtures.

The conversation with PMs: "We have an API test for 'can't add to cart with invalid quantity.' Do we also need a UI test? Yes — but only one, asserting the inline error displays. Not five for every quantity edge case."

The cultural signal: the QA team treats the test pyramid as a contract, not a slogan. Pull requests that add UI tests for behaviours covered at API are flagged in code review.

// WHAT INTERVIEWERS LOOK FOR

Clear principle (each layer tests what only it can), explicit lists of API-layer vs UI-layer concerns, and the discipline to push back on duplicated UI coverage.

// COMMON PITFALL

'We test it at both layers for safety' — the slogan that quietly doubles the suite cost. Confidence is good; duplication is not. Trust each layer to do its job.