A bug report has one job: help the developer reproduce, understand, and fix the issue as fast as possible. Every minute the developer spends asking "what browser?" is a minute they are not fixing the bug. The difference between a tester whose bugs get fixed in 24 hours and one whose bugs sit untouched for weeks is rarely how good the bugs are — it is how well the reports are written.
The essential fields
A useful bug report has seven fields, and skipping any one costs the team time:
- Title — descriptive enough that the dev can decide whether to investigate before opening the ticket.
- Environment — browser and version, OS and version, URL or build ID, test account.
- Steps to reproduce — numbered, starting from a clean state, deterministic.
- Expected result — what should happen, ideally tied to a test case ID or acceptance criterion.
- Actual result — what actually happened, in observable detail.
- Screenshots / video — annotated where helpful.
- Severity / priority — how bad it is and how urgent it is.
Trackers often add fields like component, affects-version, and labels — useful for triage but secondary.
The title is the most important field
A bug title is the first thing the developer reads, and often the only thing they read before deciding whether to investigate now or defer. Compare:
- ❌ "Login bug." Useless. Tells the dev nothing.
- ❌ "Login fails." Better, but still incomplete — fails how? When?
- ✅ "Login fails silently with special characters in password on Firefox 127 / Windows 11."
The third version names the feature, the symptom, the trigger, the browser, and the OS. A developer reading their morning queue knows in two seconds whether this is "for me" — and once the ticket is open, they already have a strong guess at where the bug lives.
A useful structural pattern: [area] [verb] [condition] on [environment]. Apply it consistently and your queue becomes scannable.
Steps that reproduce on the first attempt
Steps to reproduce are a recipe. The bar: a developer should reproduce the bug on the first try, without asking. Three habits get you there. Start from a clean state — "log out, clear cookies, new private window..." If the bug needs a specific state, name it. Be specific about inputs — quote exact strings (O'Brien, test@example.com), not "a name with apostrophe." One action per step — bundling actions makes it ambiguous which one triggered the bug.
Screenshots and video
A 10-second screen recording can replace 200 words. macOS: Cmd+Shift+5. Windows: Win+G Game Bar. Linux: built-in recorder or OBS. For static issues, a screenshot is enough — but annotate it. A red box around the bug area and a one-sentence caption is roughly 10× as useful as a raw one. The bug report format cheat sheet has a copy-pasteable template.
Severity vs priority — they are different
These two terms are confused constantly. They measure different things:
- Severity is how bad the bug is technically. A crash is high severity. A typo is low severity.
- Priority is how urgently the team should fix it. A typo on the homepage in a launch screenshot is low severity but high priority. A crash that affects 0.001% of users is high severity but probably medium priority.
Never set priority based purely on severity, or vice versa. The right scoring needs both — a severity-vs-priority decision is one of the most useful skills a junior tester can develop.
A complete example
A bug report for a checkout rounding error might read:
- Title: Cart total displays £20.00 for an item priced £19.99 on Chrome and Safari (rounding bug).
- Environment: Chrome 127 / macOS Sonoma; reproduced on Safari 17 / iOS 17. Staging build #4421. Test account
test+rounding@example.com. - Steps: (1) Open
https://staging.acme.com, log in with the test account. (2) Navigate to the headphones product page (/products/wireless-headphones-19-99). (3) Click "Add to cart." (4) Open the cart drawer. - Expected: Cart total reads
£19.99, matching the product's listed price. - Actual: Cart total reads
£20.00. The discrepancy persists in the order summary on/checkout. Network response fromPOST /cart/addreturnstotal: 1999(correct in pence); the front-end renders£20.00. - Screenshot: annotated screenshot attached, with a red box around the £20.00 total and the £19.99 price label.
- Severity: High (real money difference). Priority: P1 (every customer with a
.99-priced item is over-charged).
A developer can pick up that ticket, reproduce it in 60 seconds, and have a strong hypothesis about where to look (the front-end currency formatter) before opening the code.
The full life of a bug
Step 1 of 6
Find
Tester encounters the bug — through a planned test case, exploratory testing, or a customer report.
Each step is short when the previous step was done well. A weak report inflates every downstream step.
⚠️ Common mistakes
- Vague titles. "Login bug" wastes everyone's time — the developer has to open the ticket just to learn what it is. Always name the area, the symptom, and the environment.
- Skipping environment details. "Doesn't work" without browser, OS, and URL forces the developer to guess. Most "can't reproduce" closures are about missing environment info, not the bug being fake.
- Conflating severity with priority. A high-severity, low-priority bug is a real category, and so is the inverse. Score both axes; let the team prioritise from the combined picture.
🎯 Practice task
Spend 25 minutes upgrading your bug-reporting reflex.
- Open your last 5 closed bug tickets. Re-read each one as if you were a developer who had never seen the feature. Could they reproduce on the first try? Was the title scannable?
- Pick the weakest one and rewrite it using the seven-field template. Time how long the rewrite takes.
- The next bug you find, record a 10-second video walkthrough alongside the written steps. Notice how much faster the developer asks for clarification (or doesn't).
- For one open bug, separate severity and priority into two distinct values with a one-line justification each. The clarity of that distinction often surfaces a hidden disagreement about why a bug matters.