Smoke, Sanity, Regression, and Retesting

Clear distinctions between smoke, sanity, regression, and retesting: when to use each and which terminology mistakes disrupt teams.

Updated:

Contents

These four terms are often mixed together, creating different expectations of scope and disputes over wording. Agreeing on a shared team meaning matters more in practice than debating the correct textbook definition.

Smoke testing

Smoke testing quickly establishes whether the system is broadly operational and suitable for further testing or use. It usually includes the most critical happy paths: startup, login, basic navigation, creating a core entity, and main API availability.

Sanity testing

Sanity testing is a narrow, targeted check of a specific change or problem area. After a small discount-calculation change, for example, the team checks related scenarios and neighboring areas rather than the whole product.

Regression testing

Regression testing rechecks existing functionality to confirm new changes have not broken previous behavior. It is usually broader than smoke or sanity testing and follows known product risks.

Retesting

Retesting, also called confirmation testing, checks a specific fixed defect: is the bug resolved in the scenario where it was found? It does not replace regression testing because it does not establish what else may have been affected.

Practical distinctions

  • →Smoke: is this build suitable for continued testing?
  • →Sanity: does the specific area still behave as expected after a local change?
  • →Retesting: was this particular defect fixed?
  • →Regression: did changes affect other functionality?

Practical guidance

  • →Document a shared team vocabulary so everyone understands scope consistently.
  • →Build regression testing around risk rather than an arbitrary selection of old cases.
  • →Do not treat retesting alone as sufficient release evidence when the change affects dependent areas.

Choose by purpose: a release with a discount fix

Fictional requirement DISC-1: apply a 10% discount when the goods subtotal is at least 10000 cents. A reported defect used > instead of >=, so a 10000-cent basket received no discount. All amounts below yield whole-cent results; other amounts need an explicit rounding rule. The release changes this comparator in a shared total-calculation function.

plain text
Check	Purpose	Trigger	Scope	Example
Smoke	Is the build usable for further testing?	New deployment	Small set across critical features	App opens, login works, catalog loads, checkout opens
Sanity (team convention here)	Does the changed area behave plausibly?	Small targeted fix	Focused neighborhood	Subtotals 9900 / 10000 / 10100 yield 9900 / 9000 / 9090
Retest / confirmation	Was the reported defect corrected?	Fix for a known issue	Original reproduction and expected outcome	Same 10000-cent basket now returns 9000
Regression	Did the change damage existing behavior?	Change with potential impact	Risk-selected related and dependent features	Saved orders, invoices and refund calculations still match their approved expectations

One release, four separate questions

First run the environment smoke. If checkout cannot open, record a blocker; a failed deployment does not prove the comparator fix is wrong. Next repeat the exact defect setup, account, currency and input on the new build: 10000 must produce 9000. That is confirmation. Then probe the nearby 9900 and 10100 values with the focused set; the team may call that sanity testing.

For regression, inspect callers of the shared calculation before selecting tests. Include stored-order totals, invoice totals, and any refund path that actually calls the function. Reconcile each against an agreed saved expected result for its own rules; do not assume a refund is automatically 90% or that every consumer shares DISC-1. Add a previously valid non-discounted basket as a control. Breadth follows dependency and business-risk evidence, not a fixed test-count rule.

A small executable demonstration

Save as release_check_selection.py and run python3 release_check_selection.py. Expected output: Known defect reproduced; confirmation and three focused checks passed. This script demonstrates the arithmetic and selection logic only: it does not execute an application smoke or the dependent-feature regression suite.

plain text
def old_total(cents):
    return cents * 9 // 10 if cents > 10000 else cents

def fixed_total(cents):
    return cents * 9 // 10 if cents >= 10000 else cents

# Values below produce whole-cent results; no rounding rule is inferred.
assert old_total(10000) == 10000
assert fixed_total(10000) == 9000
for cents, expected in [(9900, 9900), (10000, 9000), (10100, 9090)]:
    assert fixed_total(cents) == expected
print("Known defect reproduced; confirmation and three focused checks passed")

Record the boundary of the evidence

A case can belong to more than one suite: the 10000-cent check is both confirmation evidence for the issue and a useful future regression check. Do not count duplicate execution as additional behavioral coverage. Record build, purpose, actual outcome and uncovered risk so readers know what “passed” means.

Sanity has different meanings across teams and is sometimes used interchangeably with smoke. Define its scope locally instead of treating this table as a mandatory taxonomy. Confirmation and regression answer different questions; fixing the original reproduction does not establish that surrounding behavior is unchanged.

Exercise: the exact 10000-cent retest passes, but invoices still show 10000 after checkout saved 9000. Can the release be declared clean? No. The original defect may be fixed while a dependent-feature regression fails. Record both results and investigate the inconsistency rather than turning the successful retest into a release verdict.

Continue learning

Build a regression strategy around risk

Collect release evidence

Keep short operational checklists

ISTQB CTFL 4.0.1: section 2.2.3, confirmation and regression