How do you derive abuse and misuse cases from a documented happy-path flow?
answer
- Success is only half the specification
- Walk the steps, not the screens
- Ask what an actor does instead
- Omit, repeat, reorder, substitute, exceed
- Each case names its expected refusal
basics
~20 sWalk each step of the happy path and ask what an actor could do instead: skip it, repeat it, reorder it, supply another actor's identifier, or exceed a limit. Each answer becomes a case the system must refuse.
solid answer
~50 sWrite the happy path as numbered steps, recording for each step who performs it, what state it requires and what it changes. Then apply a fixed set of operators to every step: omit it, repeat it, reorder it against its neighbours, substitute the identifier with one from another actor or account, substitute the actor with an unauthenticated or lower-privileged one, exceed the expected quantity, act outside the allowed time window, and malform the payload. Each combination is a candidate case. Prune to the ones a stated rule says must be refused, plus the ones nobody can answer — those are specification gaps found early. Finish each surviving case with a precise expected refusal: what the caller sees, that no state changed, and whether the attempt is recorded. "It should not work" is not an expected result.
code
pseudocode · 13 linesstep = {id: 5, actor: "planner", action: "publish_draft", requires: ["draft_locked"], changes: ["timetable_version"]}
candidates = []
candidates.add(omit_precondition(step, "draft_locked"))
candidates.add(repeat(step, times=2))
candidates.add(reorder(step, before="run_clash_check"))
candidates.add(substitute_identifier(step, scope="other_school"))
candidates.add(substitute_actor(step, role="teacher"))
candidates.add(substitute_actor(step, role="anonymous"))
candidates.add(shift_time(step, to="after_term_start"))
for candidate in candidates:
candidate.expected = {outcome: "refused", state_change: "none", audited: true}go deeper
Be ready to take a short happy path an interviewer describes and produce misuse cases out loud. Naming the operators — omit, repeat, reorder, substitute, exceed, malform — is what gets you past this question.
Explain the mechanics: how a step's preconditions and state changes tell you which operator applies, and how you turn a candidate into a case with a checkable expected refusal rather than a vague "should fail".
Show judgement about pruning and about where each case runs. An interviewer expects you to say which candidates are worth keeping, and to insist that a case the interface makes impossible still runs at the service boundary.
Own the practice, not the list. Be ready to say how derivation gets scheduled, who reviews the undefined outcomes, and how you keep a growing catalogue of refusal cases from outgrowing the team that maintains it.
### A happy path is a sequence, not a picture A happy path is the ordered list of steps that carries an actor from an intent to a completed outcome with every precondition met and every input well formed. It is the flow the specification was written around, the flow the demo shows, and usually the only flow the suite proves. An **abuse case** is a use of the same flow by an actor whose intent is hostile; a **misuse case** is a use by an ordinary actor whose intent is innocent but whose path was never envisaged. Both produce the same artefact for a tester: a case whose expected outcome is a **refusal**, and whose oracle - the thing that says the observed behaviour is wrong - is that the refusal did not happen, or happened incompletely. The derivation is mechanical enough to do in a room with a whiteboard, which is why it is asked at screening depth. You write the happy path as numbered steps. For each step you record who performs it, what state it requires, what it changes, and what it returns. Then you apply a fixed set of operators to that step and read off the cases. ### The operators - **Omit** the step. Jump straight to step five. Does the system enforce that steps one to four happened, or does it trust the caller to have walked the sequence? - **Repeat** the step. Send the same completed action twice, or twice concurrently. Is the second one refused, ignored, or applied again? - **Reorder** the steps. Perform the confirm before the reserve. This is where the most expensive defects on this leaf usually live, because ordering is an assumption nobody wrote down. - **Substitute the identifier.** Perform the step with an identifier that belongs to a different actor, a different account or a different scope than the one the session was issued for. - **Substitute the actor.** Perform the step as an unauthenticated caller, as a lower-privileged role, and as an equally-privileged actor from a different scope. - **Exceed the quantity.** Ask for ten thousand where the flow expects three; upload past the stated limit; request a page far beyond the end. - **Stretch the timing.** Perform the step after the window closed, after the actor's access was removed, or while another actor performs the same step on the same record. - **Malform the payload.** Omit a required field, add an unexpected one, send the wrong type, send an empty collection where one item was assumed. Each operator applied to each step yields a candidate. You then prune: keep the candidates where a stated rule says the system must refuse, plus the ones where nobody can tell you what should happen - those are the valuable ones, because an undefined refusal is a specification gap discovered before it is a defect. ### A worked derivation Take a school timetable planner. The happy path for publishing a term timetable is: (1) a planner opens the draft term, (2) assigns each class to a room and a slot, (3) runs the clash check, (4) locks the draft, (5) publishes it to teachers and students. Applying the operators to step 5 alone gives: publish without having run the clash check (omit); publish twice within the same second (repeat); publish a draft that was never locked (reorder); publish a draft belonging to a different school (substitute the identifier); publish as a teacher rather than a planner (substitute the actor); publish after the term start date has passed (timing). A team of four working through five steps this way generates on the order of thirty candidates in an hour and prunes to perhaps eighteen worth keeping. The reorder case is the instructive one here: the planner had an **ordering assumption** - that a draft reaching publish must already have passed the clash check, because the interface only offers the publish control after the check completes. The service itself never re-checked. A request assembled out of order published a timetable with two classes in the same room, and the interface-level assumption was invisible until someone wrote the case that violated it. ### What the derived case must say A derived case is not finished when it names the misuse. It has to state the expected refusal precisely enough to be checkable: the outcome the caller sees, the fact that no state changed, and whether the attempt should leave a record. "It should not work" is not an expected result - it passes when the endpoint has been renamed and the request now fails for an unrelated reason. Two distinctions keep the catalogue honest. First, **must-refuse versus cannot-happen**: if a case is impossible only because the interface hides the control, it is a must-refuse case at the service boundary and must be exercised there, not through the interface that hides it. Second, **refuse versus tolerate**: a repeated submission may legitimately be absorbed rather than rejected, and the case must say which, because a test asserting rejection against a system that correctly absorbs it is a false alarm that trains people to ignore the suite.
- What is the difference between an abuse case and a misuse case, and does it change the test you write?An abuse case assumes a hostile actor deliberately working against the system; a misuse case assumes an ordinary actor taking a path nobody envisaged, such as opening two windows and submitting the same form twice. The distinction matters for prioritisation and for who reviews the list, but the artefact is identical: a case whose expected outcome is a refusal or a safe absorption, with the state change asserted either way.
- You derive a candidate case and nobody on the team can say what the system should do. What do you do with it?Treat it as the most valuable candidate in the batch. An undefined outcome is a specification gap, and it is far cheaper to close in a five-minute conversation than after a release. Take it to whoever owns the rule, get a decision recorded, and then write the case against the decision. Do not guess an expected result and encode your guess as the oracle — that bakes an unreviewed opinion into the suite.
- How do you stop this technique generating an unbounded pile of cases?The operators produce candidates, not tests. Prune by keeping the cases a stated rule requires the system to refuse, the ones with no stated answer, and the ones whose failure would be expensive or irreversible. Drop the ones already covered by an equivalent case at the same boundary. A five-step flow should yield a couple of dozen candidates and roughly two-thirds that many kept cases, not hundreds.
A building inspector does not only check that the front door opens; they try every window, the fire exit from the wrong side, and the door left propped while the alarm is armed.
saying these in an interview costs you the question
- Treating "it should not work" as a complete expected result
- Deriving cases only from screens instead of from steps
- Assuming the interface prevents an out-of-order request
- Listing misuse cases but never asserting state was unchanged
- Only varying the input, never the actor or the ordering