Use Case Testing and User Journey Mapping

7 min read

The previous techniques in this chapter — state transition, decision tables, pairwise — all chop a feature into small pieces and test the pieces. Real users do not experience features in pieces; they experience whole journeys. They book a hotel by searching, picking a room, paying, and arriving — through three different services and a dozen screens. Use case testing zooms back out to the journey level, and it is the technique that catches the bugs that only appear when many features touch each other.

What a use case actually is

A use case is a structured description of a single interaction between a user (called the actor) and the system. The standard structure has five sections:

  • Actor — who is doing this. "Logged-in customer," "anonymous visitor," "clinician."
  • Preconditions — what must be true before the use case starts. "Customer has at least one saved payment method."
  • Main flow — the happy-path steps from start to success. Numbered, in plain language.
  • Alternative flows — branches off the main flow that still end in success ("no rooms in the chosen city — show similar cities").
  • Postconditions — what must be true after the use case ends. "Booking exists with status 'confirmed' and confirmation email sent."

A complete use case is roughly half a page. It captures everything a tester needs to design the journey-level test cases.

Use cases vs user stories

Use cases and user stories are sometimes treated as competing formats. They are not. A user story captures who, what, why in one sentence — the planning artefact. A use case captures the flow — the steps that deliver the story. Stories live in the backlog; use cases live in the test plan. A team that uses one needs the other.

A real example: booking a hotel room

Consider the use case "Customer books a hotel room." The main flow is short, the alternative and error flows are where the bugs live.

Step 1 of 6

Search

Customer searches by city and dates. Main flow continues if at least one result is returned.

Notice that the journey has three kinds of arrows: the main flow, the alternative flows (still end in success), and the error flows (recoverable failures). Each one is a separate test case. Use case testing is the technique that systematically generates all three.

Deriving test cases from a use case

For each use case, you produce three families of tests:

  1. Main flow test. Walk the happy path end to end with realistic data. Every step in the flow becomes one verification.
  2. Alternative flow tests. One per alternative flow. The setup typically diverges from the main flow at a specific step — start the use case, follow the main flow until that step, then take the alternative branch and verify it still ends in success.
  3. Error flow tests. One per error flow. Trigger the error condition (force a payment decline, force a session timeout, force a network drop) and verify the system recovers gracefully — no double-charge, no silent state loss, no broken UI.

For the hotel booking use case above, that produces something like 1 main + 2 alternative + 2 error = 5 test cases. None of those tests are exhaustive on their own — they each verify one journey through the feature. Together they cover the journey-level surface area.

User journey mapping for cross-feature flows

A single use case lives within one feature. A user journey map strings multiple use cases into a longer flow. "First-time customer signs up, books a room, completes the stay, leaves a review" spans four features. Mapping at journey level surfaces a different bug category — the ones that only appear when state is passed between features.

A real example: a hotel platform discovered that a customer who booked, cancelled, and re-booked within five minutes was being marked as a "first-time guest" again, losing their loyalty status. The cancel flow's clean-up code reset a flag the booking flow relied on. No single use case test would have caught it; a journey-level "book → cancel → book again" test caught it on the first run.

When to reach for use case testing

Use case testing is the right tool when:

  • The feature is interaction-heavy with branches (booking flows, multi-step forms, sign-up wizards).
  • The bugs that matter are journey-level, not within a single screen.
  • You need a test artefact a non-tester can read — use cases work for product managers, support agents, and stakeholders, not just for engineers.

It is overkill for features that are essentially a single screen with a few inputs — equivalence partitioning and decision tables are usually enough there.

⚠️ Common mistakes

  • Testing only the main flow. It is the easiest path and the one with the fewest bugs. The alternative and error flows are exactly where the production incidents come from. Treat each alternative and error flow as a first-class test case.
  • Writing use cases as code-level descriptions. A use case should be readable by the PM or a customer support agent. If it includes "POST to /api/v2/bookings," you have written technical documentation, not a use case.
  • Forgetting postconditions. The "main flow ended in success" is only half the verification. The other half is "the system state is what we expected" — record exists, email sent, audit log updated, inventory decremented. Always assert the postconditions explicitly.

🎯 Practice task

Pick a multi-step feature you understand well — a sign-up flow, a checkout, a money transfer, a job application. Spend 25 minutes producing a use case and deriving the test cases:

  1. Write the actor, preconditions, main flow (5–8 numbered steps), and postconditions in plain language. Half a page maximum.
  2. Identify at least two alternative flows (still end in success — "user uses saved address instead of typing") and at least two error flows (recoverable failures — "payment declined," "session timeout").
  3. Derive one test case per flow. Each test case should specify the trigger, the steps, the expected result, and any postcondition assertions.
  4. Map a longer user journey that strings this use case together with one before it and one after it. List one bug that could exist only across the seams between use cases.

The final lesson of this chapter brings the topic back full circle — to the experience-driven techniques that complement the structured ones we have studied so far.

// tip to track lessons you complete and pick up where you left off across devices.