The common advice is terrible: 'Write clear reproduction steps and you'll be fine.' That's like saying 'Buckle your seatbelt and you'll never crash.' Reproduction isn't a single step you write once. It's a thread that runs through every stage of a bug's life—from the moment it's opened to the moment it's closed. If you don't treat it as a lifecycle, you'll drown in 'Cannot Reproduce' and waste weeks on ghosts.
Imagine you're a QA engineer at a mid-size SaaS company. You've just been handed a bug report from a support agent: 'User can't save a form after uploading an image. Works for me.' Sound familiar? That's the classic 'Cannot Reproduce' death spiral. The standard fix is to ask for more details. But that's reactive. You need to build reproduction into the system from the start.
Step 1: The Report Is a Contract, Not a Wish
Every bug report is a contract. The reporter promises that the steps lead to the failure. The developer promises to verify them. If the contract is sloppy, the whole lifecycle breaks. A complete defect report needs reproduction steps, expected vs actual behavior, severity and priority, environment details, and visual proof. (Atlassian bug life cycle) That's not a checklist—it's the foundation. Without it, you're building on sand.
But here's the kicker: even a perfect report isn't enough. Because reproduction isn't just about the initial steps. It's about what happens after the developer says 'fixed.'
Step 2: The Lifecycle Is a Loop, Not a Line
A defect typically moves through New/Open, Assigned, In Progress, Fixed, Pending Retest, Retest, Verified, and Closed. (Atlassian bug life cycle) Notice that 'Retest' is in there. That's your second chance to reproduce. Most teams treat retest as a formality—'did the build pass?' But retest is where you confirm the fix actually addresses the root cause. If you didn't reproduce it the first time, how do you know the fix works?
And what about the states that aren't on the happy path? Rejected, Duplicate, Deferred, Reopened, Not a Bug, and Non-Reproducible. (Atlassian bug life cycle) 'Non-Reproducible' is the graveyard of bugs. It's where reports go to die. But it's only a graveyard because we treat reproduction as a one-shot event. If you treat it as a lifecycle, 'Non-Reproducible' becomes a temporary state, not a final verdict.
Step 3: The 'Power of 10' for Reproduction
NASA's Jet Propulsion Laboratory faced a similar problem with software defects. Gerard Holzmann proposed 'The Power of 10: Rules for Developing Safety-Critical Code'—a small set of rules that can easily be remembered, clearly relate to risk, and allow automated compliance checking. (NASA NTRS Spinoff 2011) The point isn't the rules themselves; it's the philosophy. You need a small, memorable set of reproduction rules that you can actually enforce.
Here's my Power of 10 for reproduction:
- Reproduction steps must be numbered and in order.
- Every step must include the exact input (data, clicks, keystrokes).
- Environment details must include OS, browser, version, and any relevant settings.
- Expected vs actual behavior must be stated separately.
- Visual proof (screenshot, video) is mandatory for UI bugs.
- If the bug is intermittent, note the frequency and any pattern.
- If you can't reproduce it, say so—and say what you tried.
That last one is crucial. Admitting you can't reproduce is the first step to fixing that.
Step 4: Use Combinatorial Testing to Find the Hidden Trigger
Why do some bugs only appear with specific combinations of actions? Because software failures often depend on multiple parameters interacting. NIST research shows that virtually all software failures appear to be caused by six or fewer parameter interactions, so exhaustive checking of all input combinations is unnecessary. (NIST 2010) That's a powerful insight for reproduction. Instead of trying every possible combination, you can use combinatorial testing to target the most likely interactions.
In your scenario, the bug might only occur when the user uploads an image, then changes the file name, then hits save. That's three parameters. With combinatorial testing, you'd test those pairs systematically. It's not a silver bullet, but it gives you a structured way to hunt for the trigger.
Step 5: Track Reproduction in Your Bug Tracker
Your bug tracker should reflect the reproduction lifecycle. That means adding fields for 'Reproduction status' (e.g., Reproduced, Not Reproduced, Partial) and 'Reproduction attempts.' Bugzilla was created specifically to handle workflow management, bug-visibility control, and custom fields. (Bugzilla official site) If you're using Jira, you can add custom fields too. The point is to make reproduction visible, not hidden in comments.
And don't forget the lifecycle of security vulnerabilities. They follow a separate path, but the same principle applies. The NVD enriches every CVE with CVSS scores, CWE types, and CPE applicability. (NVD) That's their way of standardizing reproduction—the 'environment' for a vulnerability is the vulnerable software version. If your bug tracker doesn't capture the environment, you're flying blind.
Step 6: Learn from the Mars Global Surveyor
Here's a cautionary tale. NASA's Mars Global Surveyor operated successfully for more than 9 years before the mission ended because a software update written months earlier was stored at the wrong memory address. (NASA NTRS Spinoff 2011) That bug wasn't caught because it wasn't reproduced in the right context. The update worked in testing but failed in the real environment. Reproduction isn't just about steps; it's about the environment. If you don't capture the exact environment, you'll miss the bug that only appears in production.
So, in your bug report, the 'environment details' field is as important as the steps. Don't let it be an afterthought.
Step 7: The Retest Is Your Second Chance
When the developer marks the bug as 'Fixed,' it goes to 'Pending Retest.' This is your moment to shine. Don't just run the original steps—run them again, but vary the environment slightly. Try a different browser, a different user role, a different file. If the bug was intermittent, run it multiple times. And if you find a new defect during retest, log it as a separate issue. (Atlassian bug life cycle) That keeps the lifecycle clean.
If you still can't reproduce it, don't just close it as 'Non-Reproducible.' That's a dead end. Instead, mark it as 'Needs More Info' and go back to the reporter. Ask for a screen recording, a HAR file, or any other artifact that might reveal the trigger. The key is to keep the loop alive.
What I'd actually do
My concrete recommendation: adopt a reproduction-centric lifecycle in your tracker. Add a custom field for 'Reproduction Status' with values: Reproduced, Not Reproduced, Partial, Blocked. Require that any bug in 'Not Reproduced' status cannot be moved to 'Fixed'—it must go back to the reporter for more info. And enforce a 'retest with variation' policy: every retest must include at least one environmental change from the original report. This won't eliminate 'Cannot Reproduce' overnight, but it will shrink it dramatically. Because reproduction isn't a step—it's a habit. And habits take practice.
Sources
- Atlassian - https://www.atlassian.com/software/jira/guides/bug-tracking/bug-life-cycle
- NIST - https://www.nist.gov/news-events/news/2010/11/updated-nist-software-uses-combination-testing-catch-bugs-fast-and-easy
- NASA - https://ntrs.nasa.gov/api/citations/20120001915/downloads/20120001915.pdf
- Bugzilla - https://www.bugzilla.org/about/
- NVD - https://nvd.nist.gov/general
Comments (0)
Please sign in to post a comment.
Don't have an account? Create one
No comments yet. Be the first to comment!