Open this lesson in your favourite AI. It'll walk you through the why, explain the demo, and quiz you on the try-it list.
A bug report that says 'the login doesn't work' is useless. A bug report that says 'Login with valid credentials returns HTTP 500 on Chrome 124/macOS when the email contains a + character — reproduces 100% of the time, HAR file and screen recording attached' gets fixed the same day. Great bug reports save developer time, reduce back-and-forth, and build your credibility as a QA engineer. Poor reports waste everyone's time and cause bugs to be closed as 'cannot reproduce.' The anatomy of a great bug report is learnable and consistent: title, steps, expected, actual, severity, priority, environment, and evidence.
Bug report quality directly predicts fix time — a report with clear steps, environment, and expected vs actual result gets fixed in hours; a vague one spends three days in 'cannot reproduce.' The template enforces the fields that convert a developer's mental model of 'what could cause this?' into a testable hypothesis. Validation catches the anti-patterns (vague titles, missing environment, circular expected/actual) before the report reaches the queue.
from dataclasses import dataclass, field
from typing import List, Optional
import re
@dataclass
class BugReport:
title: str
steps: List[str]
expected: str
actual: str
severity: str # critical | high | medium | low
priority: str # P1 | P2 | P3 | P4
environment: str # browser, OS, version
reproducibility: str # always | intermittent | once
attachments: List[str] = field(default_factory=list)
def validate(self):
errors = []
if len(self.title) < 20:
errors.append("Title too vague — be specific about what fails and where")
if len(self.steps) < 2:
errors.append("Need at least 2 steps to reproduce")
if self.expected == self.actual:
errors.append("Expected and actual results are identical — not a valid bug")
vague_words = ["doesn't work", "broken", "not working", "fails", "error"]
if any(w in self.title.lower() for w in vague_words) and len(self.title) < 50:
errors.append("Title uses vague language — describe the specific symptom")
return errors
def render(self):
print(f"TITLE: {self.title}")
print(f"SEVERITY: {self.severity} | PRIORITY: {self.priority}")
print(f"REPRODUCIBILITY: {self.reproducibility}")
print(f"ENVIRONMENT: {self.environment}")
print(f"STEPS:")
for i, s in enumerate(self.steps, 1):
print(f" {i}. {s}")
print(f"EXPECTED: {self.expected}")
print(f"ACTUAL: {self.actual}")
if self.attachments:
print(f"EVIDENCE: {', '.join(self.attachments)}")
bad_report = BugReport(
title="Login broken",
steps=["Go to login"],
expected="Works",
actual="Doesn't work",
severity="high", priority="P1",
environment="Chrome",
reproducibility="always",
)
good_report = BugReport(
title="Login returns HTTP 500 when email contains a + character",
steps=["Navigate to /login", "Enter email: user+tag@example.com", "Enter valid password", "Click Login"],
expected="Redirect to /dashboard with 200 OK",
actual="HTTP 500 Internal Server Error — 'Invalid email format' in response body",
severity="high", priority="P2",
environment="Chrome 124 / macOS 14.4 / App v2.3.1",
reproducibility="always",
attachments=["screen-recording.mp4", "network-har.json"],
)
print("\n=== BAD REPORT ===")
errors = bad_report.validate()
if errors:
for e in errors: print(f" ⚠ {e}")
print("\n=== GOOD REPORT ===")
errors = good_report.validate()
if errors:
for e in errors: print(f" ⚠ {e}")
else:
print(" ✓ Passes all validation checks")
good_report.render()python3 main.pyvalidate(). Did it pass? Fix any validation failures.severity_vs_priority_check() validator: a Critical severity bug must be P1 or P2 — flag it if it's P3/P4. Also flag P1 priority bugs that have severity 'low'. This enforces the distinction: severity = impact on the system, priority = urgency of fix.estimated_impact: str field (e.g., '100% of users trying to register with + in email are blocked'). Write 3 bug titles — then rewrite each to include this impact. Compare the two versions for clarity.Use these three in order. Each builds on the one before.
In one paragraph, explain the difference between bug severity and priority. Give a concrete example of a high-severity/low-priority bug and a low-severity/high-priority bug.
Walk me through what makes a bug 'cannot reproduce': what information is typically missing from the bug report that would have allowed the developer to reproduce it? List at least 4 common missing pieces.
I'm setting up a bug triage process for a 5-person QA team filing 50+ bugs per sprint. What fields should be mandatory in your bug tracker, what fields are optional, and what SLAs would you set for each severity level (time from filed to acknowledged, time from acknowledged to fixed)?