Finding a defect is only the beginning. What happens after discovery — how the defect is reported, assigned, fixed, verified and closed — determines whether the bug actually gets resolved or disappears into a backlog graveyard. The defect life cycle is the structured workflow that every bug follows from the moment a tester discovers it to the moment it is confirmed fixed and closed. Understanding this cycle is essential because your role as a QA engineer does not end when you file the bug — it ends when you verify the fix and close the ticket.
Defect Life Cycle — Status Transitions and Responsibilities
Every defect tracking system uses a set of statuses that represent where a bug is in its journey. While exact status names vary between tools, the underlying flow is consistent across the industry.
# Modelling the defect life cycle with status transitions
DEFECT_LIFECYCLE = {
"New": {
"description": "Tester has discovered and reported the defect",
"owner": "QA Engineer",
"next_states": ["Open", "Rejected"],
"action": "Triage team reviews the defect report",
},
"Open": {
"description": "Defect accepted and assigned to a developer",
"owner": "Development Lead",
"next_states": ["In Progress", "Deferred"],
"action": "Developer is assigned and begins investigation",
},
"In Progress": {
"description": "Developer is actively working on the fix",
"owner": "Developer",
"next_states": ["Fixed"],
"action": "Developer implements and unit-tests the fix",
},
"Fixed": {
"description": "Developer has committed a fix; ready for QA verification",
"owner": "Developer",
"next_states": ["Verified", "Reopened"],
"action": "QA engineer re-tests the scenario from the original report",
},
"Verified": {
"description": "QA confirms the fix works; defect is resolved",
"owner": "QA Engineer",
"next_states": ["Closed"],
"action": "QA marks the defect as verified after successful re-test",
},
"Closed": {
"description": "Defect is fully resolved and archived",
"owner": "QA Engineer / Manager",
"next_states": [],
"action": "No further action required",
},
"Reopened": {
"description": "QA re-test failed — the fix did not work or caused a regression",
"owner": "QA Engineer",
"next_states": ["In Progress"],
"action": "Sent back to developer with updated reproduction steps",
},
"Rejected": {
"description": "Triage team determined it is not a valid defect",
"owner": "Triage Team",
"next_states": ["Reopened", "Closed"],
"action": "Reason documented: duplicate, works as designed, not reproducible",
},
"Deferred": {
"description": "Valid defect but will not be fixed in this release",
"owner": "Product Owner",
"next_states": ["Open"],
"action": "Scheduled for a future sprint with documented justification",
},
}
print("Defect Life Cycle — Status Transitions")
print("=" * 60)
for status, info in DEFECT_LIFECYCLE.items():
transitions = " → ".join(info["next_states"]) if info["next_states"] else "(terminal)"
print(f"\n [{status}]")
print(f" {info['description']}")
print(f" Owner: {info['owner']}")
print(f" Transitions to: {transitions}")
Common Mistakes
Mistake 1 — Closing defects without verification
❌ Wrong: Developer marks a bug as “Fixed” and the QA engineer closes it immediately without re-testing.
✅ Correct: QA engineer deploys the new build to the test environment, re-executes the original reproduction steps, confirms the defect is resolved, checks for regressions, and only then moves the status to “Verified” and subsequently “Closed.”
Mistake 2 — Filing duplicate defects instead of checking existing reports
❌ Wrong: Finding a bug and immediately filing a new report without searching the defect tracker for existing reports of the same issue.
✅ Correct: Searching the defect tracker by keywords, module and error message before filing. If a duplicate exists, add your reproduction details as a comment on the existing ticket instead of creating a new one. Duplicates waste triage time and fragment the defect history.