Lesson 6 of 11 · Software Testing Fundamentals
The Bug Lifecycle
The states a defect moves through from New to Closed, who moves it, what each resolution means, and how to write defect reports that get fixed instead of bounced.
beginner 9 min read Updated
You will learn to
- Describe the common defect states and the transitions between them
- Explain resolutions such as Duplicate, Not a bug, Deferred and Cannot reproduce
- Write a defect report with everything a developer needs to reproduce it
- Distinguish confirmation testing from regression testing after a fix
Prerequisites
- STLC: The Software Testing Life Cycle
Finding a bug is half the job. The other half is getting it understood, prioritised, fixed and verified without it getting lost, bounced between people or quietly reopened three releases later. The bug lifecycle (or defect lifecycle) is the set of states a defect report moves through and the rules for moving between them. Every tracker, whether Jira, Azure DevOps, Linear or GitHub Issues, implements some version of it.
There is no single official lifecycle. ISTQB describes defect management as a process with a workflow and states that the organisation defines, and each team configures its own tool. The states below are the ones you will meet most often and the ones interviewers expect you to describe.
First, the vocabulary
Following ISTQB usage: a person makes an error (mistake), which introduces a defect (bug, fault) into a work product such as code or a requirement. When defective code runs, it can cause a failure: the system does something it should not. Testers usually observe failures and report them; developers find and fix the underlying defect. A defect report is the record of the observed problem. “Bug” and “defect” are used interchangeably in most teams.
The common states
| State | Meaning | Usually set by |
|---|---|---|
| New | Reported, not yet reviewed | Tester (reporter) |
| Triaged / Open | Reviewed, accepted as a valid problem, severity and priority agreed | Lead, triage meeting, product owner |
| Assigned | A developer owns it | Lead or developer |
| In progress | Being investigated or fixed | Developer |
| Fixed / Resolved | Code change made, waiting for a build and verification | Developer |
| Ready for test | Fix deployed to a test environment | Developer or pipeline |
| Verified | Tester confirmed the fix works | Tester |
| Closed | No further work | Tester or lead |
| Reopened | The fix did not work or the problem came back | Tester |
The main flow is:
New -> Triaged -> Assigned -> In progress -> Fixed -> Ready for test -> Verified -> Closed
|
v
Reopened -> Assigned ...
Alternative outcomes from triage
Not every report becomes a fix. These resolutions close or park the report for a stated reason:
| Resolution | Meaning | What a tester should do |
|---|---|---|
| Duplicate | Same root problem already reported | Link to the original; add any new information there |
| Not a bug / Works as designed | Behaviour matches the specification | Check the spec; if the spec is wrong, raise it as a requirement issue |
| Cannot reproduce | Developer could not see the failure | Add environment details, data, logs, a video; retry on a clean setup |
| Deferred / Won’t fix now | Valid, but not worth fixing in this release | Make sure the risk is recorded and visible |
| Won’t fix | Valid, but will never be fixed (cost, obsolete feature) | Accept, or escalate with a business argument |
| Need more info | Report is incomplete | Answer quickly; stale reports die |
Who does what
The lifecycle only works when each transition has a clear owner.
- Reporter (tester): writes a reproducible report, sets initial severity, attaches evidence, verifies the fix, closes or reopens.
- Triage group (often a lead, product owner and a developer): confirms validity, agrees severity, sets priority, assigns.
- Developer: investigates, fixes, links the code change, explains the root cause and the scope of the change.
- Product owner: decides priority, deferrals and won’t-fix calls, because those are business decisions.
Severity describes the impact; priority describes the scheduling decision. The difference matters at triage and is covered in Severity vs Priority.
Writing a report that survives triage
A defect report must let someone who has never seen the problem reproduce it in minutes. The essential fields:
| Field | Good example |
|---|---|
| Title | Checkout total ignores fixed-amount discount when cart has 2+ items |
| Environment | QA, build 2026.11.3 (commit 4f2a9c1), Chrome 142 on Windows 11 |
| Preconditions | Logged in as qa.buyer@example.com; code TENOFF (10.00 fixed) active |
| Steps | 1. Add product A (20.00) and product B (15.00). 2. Go to checkout. 3. Apply TENOFF. |
| Expected result | Discount line shows -10.00; total 25.00 |
| Actual result | Discount line shows -10.00; total still 35.00 |
| Frequency | Every time (5 of 5) |
| Evidence | Screenshot, video, POST /api/cart/discount response body |
| Severity | Critical (customers overcharged) |
| Notes | Works with 1 item; percentage codes unaffected |
Good titles state what is wrong and where, not “Checkout broken”. The Notes line, where you record what you tried and what did not fail, is often the most useful part for a developer because it narrows the search. The Bug Report Generator gives you this structure as a fill-in template.
After the fix: confirmation and regression
When a fix reaches Ready for test, two different activities follow:
- Confirmation testing (also called retesting): rerun the exact steps from the report, on the build that contains the fix, and check the failure no longer occurs. Also try close variations: if the bug was with two items, try three; if it was with a fixed code, try a percentage code.
- Regression testing: check that the change did not break something else. A fix in discount calculation can affect tax, order totals in emails, and refund amounts. See Regression Testing.
Only after both should the defect move to Verified and Closed. If the original steps still fail, reopen it with a comment stating the build you tested and what you saw. If the original steps pass but you found a new, different problem, raise a new report rather than reopening.
When to reopen versus raise new
| Situation | Action |
|---|---|
| Original steps still fail on the fixed build | Reopen |
| Original steps pass; a close variation still fails with the same root cause | Reopen, with the variation |
| Original steps pass; a different feature broke | New report, linked to the original |
| Original issue returns months later after another change | Usually a new report (a regression), linked to the original |
Lifecycle in automated suites
Automated tests interact with the lifecycle too:
- A failing automated test is a symptom to investigate, not automatically a bug report. It may be a product defect, a test defect, an environment problem or flakiness.
- When a known defect makes a test fail, mark the test as expected-to-fail (or, failing that, skipped) with a link to the defect rather than deleting it. In Playwright you can use
test.fail(); in pytest,@pytest.mark.xfail(reason="BUG-231"); JUnit 5 has no expected-failure marker, so teams use@Disabled("BUG-231"). When the fix lands, the annotation tells you which test to re-enable. - Every fixed defect is a candidate for a new automated regression test so the same bug cannot come back silently.
import { test, expect } from '@playwright/test';
// BUG-231: fixed-amount discount ignored with 2+ items. Remove test.fail() when fixed.
test('fixed discount applies to multi-item cart', async ({ page }) => {
test.fail();
await page.goto('/cart?seed=two-items');
await page.getByLabel('Discount code').fill('TENOFF');
await page.getByRole('button', { name: 'Apply' }).click();
await expect(page.getByTestId('order-total')).toHaveText('25.00');
});
test.fail() tells Playwright the test is expected to fail: it is reported as passing while the bug exists, and it is reported as a failure once it unexpectedly passes, which is your signal that the fix is in and the annotation should be removed.
Metrics people track (and their limits)
Teams often look at open defects by severity, defect age, reopen rate, and defects found after release. These are useful for spotting trends, such as a rising reopen rate suggesting rushed fixes. They are poor measures of individual performance: rewarding testers for the number of bugs raised encourages duplicates and trivial reports, and penalising developers for bug counts discourages honest reporting.
Practice exercise
You report: “Profile photo upload fails for PNG files over 2 MB.” The developer resolves it as Cannot reproduce with the comment “Uploaded a 3 MB PNG, works fine.”
- List five pieces of information that might explain why the developer could not reproduce it.
- Rewrite the report title and add any fields that were missing.
- After a fix, the original 3 MB PNG uploads, but a 3 MB JPEG now fails. What do you do with the original report and the new problem?
Show a model answer
1. Possible missing information
- Environment and build: the developer may have tested locally, not on QA, where an upload size limit is configured at the proxy.
- Browser and OS: the upload component might behave differently in Safari.
- The specific file: dimensions, colour profile, or transparency, not just size. Attach the actual file.
- Account type: free accounts may have a lower limit.
- The exact error: UI message, HTTP status of the upload request (for example 413 Payload Too Large), and the response body.
2. Improved report
Title: “Profile photo upload returns 413 on QA for PNG files above 2 MB (free account)”. Add environment (QA, build number, browser), preconditions (free-tier user), the attached test file, the network response, and frequency (every time, 4 of 4).
3. After the fix
The original issue is fixed, so move it to Verified and Closed after confirmation testing. The JPEG failure is a different symptom, possibly a regression introduced by the fix, so raise a new report, link it to the original, and mention it is likely caused by the change. If your team treats any failure in the same area after a fix as a failed fix, reopening is acceptable, but be explicit about which behaviour you tested.
Key takeaways
- The typical lifecycle is New, Triaged, Assigned, In progress, Fixed, Ready for test, Verified, Closed, with Reopened as the loop back. Teams customise it.
- Triage can also end in Duplicate, Not a bug, Cannot reproduce, Deferred or Won’t fix; each needs a specific response.
- A good report has a precise title, environment, preconditions, steps, expected and actual results, frequency and evidence.
- After a fix, do confirmation testing and regression testing before closing.
- Keep one bug per report, and turn fixed bugs into automated regression checks where it pays off.
Key terms
Finished this lesson?
Progress is saved in this browser. No account needed.