All insights
Learning

Monkey Testing: From Random Crash to Reusable Case

Monkey testing finds crashes cheaply, but only pays off if the crash becomes a reproducible test case. Here's how that handoff works.

Sep 22, 20266 min read
Monkey Testing: From Random Crash to Reusable Case — Tesbo

A mobile QA lead once described her weekend on call like this: the app crashed for a user who'd tapped the back button 40 times in a row while a video was still buffering. Nobody had written a test case for that, and nobody ever would have. That's the honest pitch for monkey testing. It's cheap, it's fast, and it finds the crashes that live in the gap between what a person would think to try and what a phone actually lets someone do.

But here's what most explanations of monkey testing leave out. Finding the crash is the easy 10%. The value only shows up if that crash turns into something the team can act on later, a reproducible case the test suite actually keeps. This post is about that handoff, because it's the same handoff every exploratory tester already knows, and it's the part that decides whether monkey testing was worth running at all.

What monkey testing actually is

Monkey testing throws random input at an application and watches for it to break. No script, no expected outcome, no test case. Just input, over and over, faster than a person could type it.

There are two flavors worth telling apart.

  • Dumb monkey testing fires input with no awareness of the app's state. It taps random coordinates on screen, regardless of whether a button is even there.
  • Smart monkey testing has some awareness of valid actions. It knows which buttons exist and taps among them, but still picks which one and how often at random.

Dumb monkey testing finds crashes faster because it doesn't waste time reasoning about anything. Smart monkey testing finds deeper crashes because it can navigate past a login screen instead of getting stuck tapping it forever.

Where it genuinely earns its place

Monkey testing is good at exactly one job. It surfaces crashes and unhandled exceptions from input combinations nobody would think to try on purpose. A person designing test cases writes down the paths that make sense: tap the play button, then pause, then seek forward. A monkey doesn't know what makes sense.

So it tries the play button 200 times in half a second. It seeks while the app is still loading. It rotates the device mid animation. That's exactly the class of bug that survives a well designed manual and automated suite untouched.

A video streaming team once found this out directly. Their designed test suite covered every deliberate interaction with the player: play, pause, seek, fullscreen. A monkey test run overnight found a crash that none of it caught, triggered by pausing and seeking within 200 milliseconds of each other during buffering. No human tester would have thought to try that exact timing on purpose.

The Safari only checkout bug that reached a customer usually isn't found this way, because that's a logic bug, not a crash. Monkey testing doesn't find logic bugs. It finds the app falling over.

The real limitation: it has no oracle

Here's the limitation that matters most, and it's structural. Monkey testing can tell you the app crashed. It cannot tell you the app gave a wrong answer.

An oracle, in testing terms, is however you know what the correct result should be. A designed test case has one built in: enter these values, expect that total. Random input has no such expectation attached to it. There's nothing to compare the result against except whether the app is still running.

If a monkey test enters a random discount code and the checkout total comes out wrong but the app doesn't crash, monkey testing will never notice. Nothing told it what right looked like. That's why monkey testing can never replace designed test cases. It operates in a different territory entirely, one where the only failure it can see is total failure.

The handoff that decides whether any of it mattered

Here's the part every existing writeup on this topic skips. A crash found by random input is worth exactly nothing until someone turns it into a reproducible case. If the crash only exists as a stack trace and a shrug, it'll happen again in three months and nobody will connect it back to anything.

The handoff works like this. When the monkey finds a crash, the tooling should capture the seed value or the exact input sequence that led to it, not just the final action. Random input is only reproducible if you can replay the randomness.

Once you have that sequence, someone manually walks it back to find the minimal set of steps that still triggers the crash. Going back to the video player example, the minimal sequence turned out to be just "pause and seek within 200 milliseconds of each other." The other 38 taps before it were noise.

That minimal sequence becomes a documented precondition on a written test case. Not a vague note that says "app crashed during monkey testing." Something specific: given the video player is buffering, when the user seeks and pauses within 200ms, then the player should not crash. That case goes into the suite the team already maintains. It gets tagged to the crash it came from and checked on every future release, so the same failure can't quietly come back.

The crash itself cost us nothing. The three months it took to notice it had come back cost us a one star review.

a mobile QA lead, on her team's postmortemQA lead

This is precisely the same handoff exploratory testing relies on. A tester wandering through the app without a script finds something odd, and the entire value of that session depends on writing down what they found in a form the team can rerun. Monkey testing is exploratory testing's less patient cousin. Same discovery, same handoff, just powered by a script instead of a person's curiosity.

What monkey testing cannot do

It's worth stating the boundary plainly. It's easy to let a cheap technique creep into doing a job it can't do. Monkey testing cannot verify business logic. It cannot check that a discount applies correctly, that a report totals correctly, or that a permission is enforced correctly. It has no concept of correct, only a concept of still running.

Teams that lean on monkey testing as a substitute for designed cases usually find that out the hard way. A logic bug ships straight through months of monkey test runs that never flagged it, because it was never going to. Monkey testing belongs in the toolbox next to designed cases and exploratory sessions, not instead of them. It's the cheapest way to catch a narrow, specific class of failure. Everything outside that class is still someone's job to design a case for.

Questions people ask

Is monkey testing the same as fuzz testing?

They're closely related. Fuzz testing usually targets APIs or file inputs with malformed or random data to find crashes and security issues. Monkey testing usually targets a UI with random interaction sequences.

How long should a monkey test session run?

Long enough to matter for your release cadence, often overnight or across a CI cycle, but there's no fixed number. Longer sessions find more, up to the point where you're just re-finding the same crash.

Can monkey testing replace exploratory testing done by a person?

No. A person exploring an app applies judgment about what looks wrong, including things that don't crash. A monkey only notices total failure.

What should I capture when a monkey test finds a crash?

The seed value or exact input sequence, the app state right before the crash, and the stack trace. Without the sequence, you can't reliably reproduce it later.

Does Tesbo generate the random input for monkey testing?

No. Tesbo doesn't run tests or generate input. It's where the reproducible case ends up once a person has turned a crash into something the team can rerun and track.

Keep going

Try Tesbo, or get the next useful idea

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

Start free

One email a month

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