All insights
Learning

Stress Testing: The Answer Is a Behaviour, Not a Number

Stress testing isn't about finding a breaking point. Here's how to write a test case whose expected result is a named failure mode, not a threshold.

Sep 20, 20267 min read
Stress Testing: The Answer Is a Behaviour, Not a Number — Tesbo

A payments team ships a release every Thursday. Every Thursday someone asks the same question in standup: what happens if checkout gets hit by ten times the normal traffic during a flash sale. Nobody has a documented answer. They have a hunch, a Slack thread from the last incident, and a load test dashboard that shows the system holding fine at 2,000 requests per second. What it does at 20,000 requests per second is anyone's guess, and that guess is not something you can put in front of an auditor or a new engineer six months from now. This post is about stress testing: writing that answer down as an actual test case, one with a precondition, a load profile, and an expected result that is not a number.

Stress Testing Is Not Load Testing With a Bigger Number

A load test asks whether the system holds at a given number. Can checkout handle 2,000 requests per second at 200 milliseconds median latency for 30 minutes. That is a threshold question with a pass or fail answer.

A stress test asks a different question: what does the system do once it stops holding. You push load past the point where it copes cleanly. Then you write down what happens next. The number that broke it is almost incidental. The behaviour at the breaking point is the actual finding.

This distinction matters. Teams that only run load tests often believe they have covered stress testing too, just because they pushed traffic higher during the load test and nothing exploded. That is not the same exercise. A load test with an unusually high target is still checking a threshold. A stress test is checking a shape of failure, and it needs its own expected result column.

The Four Things a System Can Do When It Runs Out of Room

When a system is pushed past what it can handle, it tends to do one of a small number of things. This is not a certified taxonomy from a standards body. It is a useful way to sort what teams actually observe, and most incident postmortems fit into one of these four buckets.

  • Graceful degradation: the system keeps serving requests but drops something non essential, like disabling recommendation widgets on a product page so checkout itself stays fast.
  • Queueing: incoming requests get held rather than served immediately, so a customer waits longer but still gets a result, the way a ticket booking site shows a virtual waiting room during a big on sale.
  • Load shedding: the system starts actively rejecting some requests, usually with a clear error, to protect the requests it is still able to serve. A checkout API returning a 503 with a retry hint is load shedding done well.
  • Data corruption: two requests write over each other, a payment gets recorded twice, or an order total is calculated from stale inventory. This is the one that is never acceptable.

The first three are choices a system can make on purpose. A mature architecture picks one of them deliberately for each critical path. The fourth is not a design choice. If your stress case reveals data corruption, that is a defect, full stop. If it reveals degradation, queueing, or shedding, whether that is acceptable depends on what the business decided a customer should experience under extreme load. That decision belongs in the expected result field, not in someone's memory.

Writing the Expected Result as a Behaviour

This is where most stress test documentation falls apart. Teams write "system remains stable under high load" as the expected result, which describes nothing. A stress case that is actually testable says something like this instead: at 15x normal traffic, checkout sheds new session requests with a 503 and a retry after header, while in flight payments continue to process without duplication.

That sentence has a precondition, 15x normal traffic. It has a scope, new sessions specifically rather than everything. It names a behaviour, load shedding. And it states plainly the one thing that must never happen: duplicate payments. A reviewer can read that case and know exactly what to check for. A dashboard showing "no errors" cannot tell you whether that case passed.

Recovery Is the Other Half of the Case, and Most Teams Skip It

A stress case that only checks behaviour at peak load is half finished. The far more common gap is what happens after the load drops back to normal. Does the system recover on its own, or does it stay stuck in a degraded state because a circuit breaker never reset. Does the queue drain cleanly, or do the requests that were waiting all retry at once and cause a second spike, a pattern sometimes called a thundering herd.

A team running a Black Friday drill discovered exactly this. Their checkout service shed load correctly for the two hours of peak traffic. Then it sat in a half broken state for another 40 minutes after traffic dropped, because a downstream cache never got told the surge was over. Nobody had written a test case for recovery, so nobody had checked for it, and the incident review only happened because a support queue backed up.

A complete stress case needs a second expected result for the recovery phase. What state should the system be in, and how long should that take, once load returns to normal. Writing "recovers within 5 minutes of load returning to baseline" is a testable line. Leaving it out means the case only tells half the story.

Who Actually Runs This, and Who Just Writes It Down

It is worth being direct about a division of labour that gets blurred in most tooling conversations. Generating the load itself, the tool that fires 20,000 simulated requests a second at a staging environment, is a job for a load generation or performance tool built for that purpose. That is not what a test case management tool does, and Tesbo does not generate load, apply traffic, or observe a running system's behaviour under strain.

What a test case management tool is for is the part that usually has no home at all. It is the written case that says what load profile was used, what precondition applied, which of the four behaviours was expected, and what actually happened when someone ran the drill. That record is what turns a stress test from a one off fire drill into something a team can repeat next quarter, compare against, and hand to a new engineer without a verbal history lesson.

A Stress Case for the Payments Example, Written Out

Here is what the checkout scenario from the opening looks like as an actual documented case, rather than a Slack thread.

Precondition: staging environment seeded with 50,000 active carts, payment provider sandbox configured with standard latency.

Load profile: ramp from 2,000 to 25,000 requests per second over 3 minutes, sustain for 10 minutes.

Expected result at peak: new checkout sessions receive a 503 with a retry after header (load shedding). In flight payments already accepted before the ramp continue processing with no duplicate charges and no order total miscalculation.

Expected result on recovery: error rate returns to baseline within 5 minutes of load returning to 2,000 requests per second, with no manual intervention required.

Fail condition: any duplicate charge, any order recorded with an incorrect total, or any in flight payment left in an unresolved state longer than 15 minutes.

That is a case a QA lead can hand to whoever runs the drill. It is a case an auditor can read six months later. And it is a case that gets rerun the same way every time instead of reinvented from memory each Thursday.

Questions people ask

Is stress testing the same thing as load testing?

No. Load testing checks whether a system holds at a specific number, like 2,000 requests per second. Stress testing checks what happens once the system is pushed past the point where it holds cleanly.

Are graceful degradation, queueing, load shedding, and data corruption an official industry standard?

No, this is a practical way of grouping what teams commonly observe, not a certified taxonomy from a standards body. It is useful for writing testable expected results, not for citing as an authority.

Is data corruption always a defect?

Yes. Unlike degradation, queueing, or shedding, data corruption under load is never an acceptable outcome and should always be treated as a bug.

Does Tesbo run stress tests or generate load?

No. Tesbo manages the documented test case: the precondition, the load profile, and the expected result. Generating the actual traffic is a job for a dedicated load or performance testing tool.

Why does recovery need its own expected result?

Because a system can behave correctly at peak load and still fail to recover cleanly afterward, and that failure is invisible unless someone writes down what recovery should look like and checks for it.

Keep going

Try Tesbo, or get the next useful idea

Start building your testing workflow now, or get one practical email a month.

Get started

One email a month

What we shipped, what we learned, and the occasional infographic worth pinning. Unsubscribe in one click.