Skip to content

Blog

Smoke Testing vs Sanity Testing: A Practical QA Guide

Smoke testing vs sanity testing explained for working QA teams—scope, timing, CI/CD gating, example suites, and how both relate to regression.

QA Workflow Assistant13 min read
  • smoke-testing
  • test-strategy
  • qa
  • automation

Smoke testing vs sanity testing matters most when you decide whether a fresh build deserves a full test cycle, or whether a hotfix can go out without re-running everything. Then the distinction becomes a scheduling decision with real cost.

Smoke testing asks is this build worth testing at all? Sanity testing asks did the specific thing we just changed actually work, and did it obviously break its neighbours? Both are shallow by design, and neither replaces regression.

This guide covers scope, timing, CI/CD placement, example suites, and common failure modes. For case-writing craft, start with how to write QA test cases; for suite selection, pair this with regression test cases.

What smoke testing actually verifies

A smoke test is a build-acceptance check. Its job is to prove the deployed artifact is coherent enough to justify deeper testing. The name comes from hardware: power it on, see if smoke comes out.

Practically, a smoke suite confirms that:

  • The application starts and serves its entry points
  • Critical dependencies (database, cache, auth provider, primary third-party API) are reachable
  • One representative end-to-end path completes — usually sign-in plus one core action
  • The deployment produced no obvious configuration failure, such as a missing variable or unmigrated schema

Smoke tests are broad and shallow. They touch many subsystems once and assert coarse outcomes. A smoke test should not care whether a validation message is worded correctly; it cares whether the page renders and the request returns something other than a 500.

The design constraint that matters most is runtime. A suite that takes 40 minutes is no longer a smoke suite; it is a slow gate people learn to bypass.

What sanity testing actually verifies

A sanity test is a targeted, post-change confidence check. Something specific changed — a bug fix, a config value, a library upgrade — and you want narrow verification that it landed and behaves, without committing to a full regression cycle.

Sanity testing is narrow and slightly deeper. It concentrates on one area, checks the changed behaviour properly, then samples the immediate blast radius around it.

Concretely, after a fix to password reset token expiry, a sanity pass looks like:

  1. Request a reset link and confirm it works within the valid window
  2. Confirm an expired token is now rejected with the corrected message
  3. Confirm normal sign-in still works, since auth shares the same session layer
  4. Confirm no second reset email is triggered by the fix's retry logic

That is four checks against one area, not one check against ten areas. Notice step three: sanity testing without any neighbour sampling is just "the developer said it works."

Sanity tests are also often lightly scripted — one of the few legitimate places where a tester works from a short charter rather than a formal case ID, though anything worth repeating should graduate into a written case.

Smoke testing vs sanity testing: comparison table

DimensionSmoke testingSanity testing
Core questionIs this build testable?Did this specific change work?
ShapeBroad, shallowNarrow, moderately deep
TriggerEvery new build or deploymentAfter a specific fix, config change, or patch
Scope sourceFixed list of critical journeysThe change itself plus adjacent behaviour
Typical runtimeUnder 10 minutesMinutes to under an hour
Automation fitHigh — stable, repeatableMixed — often manual or semi-scripted
OwnerUsually CI, unattendedUsually a named tester or the fixing engineer
Failure meaningStop; the build is rejectedInvestigate that area; the build may be salvageable
Documented asA standing suite with IDsA charter, or a subset of existing case IDs

The row that resolves most disputes is "scope source." A smoke suite is a fixed list agreed in advance and rarely changed. A sanity scope is derived fresh from what changed. If someone hands you a "standing sanity suite" that never varies, they have built a second smoke suite under a different name.

When each one applies in CI/CD

On every commit to the main branch

Run smoke only. Developers need a fast signal, and any gate longer than their attention span gets worked around with merge overrides. Keep it at API level where possible; API smoke is far more stable than browser smoke.

On a deploy to shared staging

Run smoke immediately after the deployment completes, against the deployed environment rather than a local server. This is where configuration failures surface: the code was fine, the environment variable was not. A pass here unblocks manual testers for the day.

After a bug fix branch is deployed

Run sanity. Testing everything is a waste; testing only the reported reproduction is too narrow. Derive a short list from the change: the fixed behaviour, its inverse, and one or two shared components it touches.

Before promoting a release candidate

Run smoke as an entry gate, then the regression core. Use sanity only for late-arriving fixes inside the release window — it is not a substitute for regression at a release boundary, no matter how tight the schedule is.

After a production hotfix

Run sanity in production against the fix, plus your smallest read-only smoke subset. Decide in advance which checks are production-safe; a hotfix window is the worst time to discover that smoke creates test orders in live payments.

Example smoke suite (illustrative B2B SaaS)

Ten checks, all coarse, all fast, no cosmetic assertions:

IDCheckLayerWhy it earns a slot
SMK-01Health endpoint returns healthy with database reachableAPICatches unmigrated or unreachable DB
SMK-02Sign-in with a seeded user returns a sessionAPIAuth gateway; nothing else matters if this fails
SMK-03Dashboard renders for a signed-in user without console errorsUIProves the frontend bundle deployed correctly
SMK-04Create a primary entity (project) via APIAPIPrimary write path
SMK-05Created entity appears in its list viewUIRead path plus indexing wiring
SMK-06Billing page loads current planUIThird-party billing integration reachable
SMK-07Background job queue accepts an enqueueAPIAsync infrastructure alive
SMK-08Email provider accepts a send in sandbox modeAPINotification dependency
SMK-09Unauthenticated request to a protected route returns 401APICheap authz guard
SMK-10Sign-out invalidates the sessionAPISession hygiene

That suite runs in a few minutes and covers most "the build is broken" mornings. It deliberately contains no field-level validation, no edge cases, and no permission matrix — those belong in the deeper packs described in regression test cases and edge case testing.

Example sanity scope for a real change

Change: a developer fixed a bug where discount codes were applied before tax instead of after, in a checkout service.

StepCheckRationale
1Order with a percentage discount shows the corrected totalThe fix itself
2Order with a fixed-amount discount shows the corrected totalSame code path, different branch
3Order with no discount is unchanged from beforeGuards against a regression in the common case
4Invoice PDF total matches the order totalDownstream consumer of the same calculation
5An existing paid order's historical total is unchangedConfirms the fix was not applied retroactively

Five checks, one area, about twenty minutes. Step five is the check that separates sanity testing from a demo.

How smoke and sanity relate to regression

Think of the four activities as scope versus depth:

ActivityScopeDepthCadence
SmokeWideVery shallowEvery build
SanityNarrowMediumPer change
Regression coreMedium-wideMediumEvery release candidate
Regression extendedWideDeepNightly or pre-release

Smoke is in practice a subset of regression — its fastest, most critical slice. Sanity is a subset of nothing; it is derived per change, which is why it resists being frozen into a standing suite.

When a sanity check catches something twice for the same feature, promote it into the regression core with an ID and an owner. That is how sanity work compounds instead of evaporating. Selection discipline for that promotion is covered in regression test cases; the field layout for the promoted case belongs in your shared QA test case template.

Step-by-step: building a smoke suite that survives contact with a deadline

1. List your top five business-critical journeys

Not ten, not twenty. Sign-in, the primary create action, the primary read action, the money path, and the exit. Write them as sentences a product manager would recognise.

2. Pick the cheapest possible proof for each

Usually an API call. Reserve UI checks for what only a browser can confirm — that the bundle loaded, the shell renders, a critical page is not blank.

3. Set a hard runtime budget first

Pick a number your team will actually wait for and treat it as a constraint. Every future addition must fit inside it or displace something else.

4. Make failures unambiguous

Each check needs a falsifiable expected result and an owner. "Dashboard looks right" is unusable at 7 a.m. when CI is red; "dashboard returns 200 and renders the account name element" is actionable.

5. Seed data deterministically

Smoke suites break most often on data assumptions. Use a fixture account created by setup code, never a hand-made account someone might delete in a cleanup sprint.

6. Gate on it, then defend the gate

A suite that can be skipped with a checkbox will be skipped. Wire it in as a blocking deploy step and require a logged override with a named approver. Then review it quarterly: if an escape was catchable inside the budget, add that check and drop your least valuable one.

Common mistakes

  1. Growing smoke into mini-regression. Someone adds "just one more" check every sprint. A year later the suite runs for half an hour and nobody trusts its failures. Enforce the budget.
  2. Calling a full regression pass "sanity testing" to make it sound cheaper. This distorts every estimate afterwards.
  3. Sanity testing only the exact reproduction steps from the bug ticket. The reported path was one symptom. Test the branch you fixed and the neighbours it shares code with.
  4. Cosmetic assertions in smoke. Asserting exact copy or pixel layout fails the gate on harmless changes, which trains everyone to re-run rather than read.
  5. Treating a smoke pass as release approval. Passing smoke means "keep testing," not "ship it."
  6. Skipping sanity because the change was "one line." One-line changes to shared calculation or auth code have the widest blast radius in the codebase.

Best practices

  • Version the smoke suite as code, in the application repository, reviewed in the same pull requests.
  • Prefer API smoke over UI smoke for anything that does not require a browser to prove.
  • Keep a documented production-safe subset so hotfix windows do not require improvisation.
  • Write sanity scope in the ticket before executing, as three to six bullets. It creates a record of what was and was not checked.
  • Automate smoke first, sanity later. Sanity varies per change and rarely repays automation until a pattern repeats.
  • Fail loudly and specifically. Include the failing check ID, environment, and deploy SHA in the notification.

For coverage depth decisions upstream of this, see Basic, Standard, or Deep coverage. If your smoke suite leans on API checks, the assertion patterns in API test cases apply directly. When reporting either level, name the limits: "Sanity passed on the discount calculation; full checkout regression has not run yet" is an honest status.

Final checklist

  • Smoke suite is a fixed, documented list with stable IDs
  • Smoke runtime budget is agreed and enforced
  • Smoke covers sign-in, one write, one read, the money path, and session exit
  • Smoke assertions are coarse, with no cosmetic checks
  • Smoke has a named owner and blocks the deploy pipeline
  • A production-safe smoke subset is documented for hotfixes
  • Sanity scope is written in the ticket before execution
  • Sanity includes the fixed branch, its inverse, and adjacent behaviour
  • Repeated sanity checks get promoted into regression with IDs
  • Reports state clearly which level of testing has and has not run

Summary

Smoke testing is a fixed, fast gate answering whether a build is worth testing. Sanity testing is a change-derived, narrow check answering whether a fix works and did not obviously damage its surroundings. Smoke belongs in automation on every build; sanity belongs to a tester who knows what changed. Regression sits above both. Keep smoke small enough to stay trusted, and promote recurring sanity checks into owned regression cases.

FAQ

Is sanity testing just a subset of regression testing?

No. Regression cases are pre-written and re-run to protect known behaviour. Sanity scope is derived from a specific change and may never be run again in that exact form. The overlap is that a useful sanity check often deserves promotion into regression afterwards.

Can one suite serve as both smoke and sanity?

Not well. A fixed suite cannot adapt to what changed, which is the point of sanity testing. Teams that try usually end up with a suite too slow to gate builds and too generic to verify fixes.

Should smoke tests run against production?

A read-only subset, yes — after deployments and during hotfix windows. Document exactly which checks are production-safe. Never let a suite that creates orders, sends real emails, or mutates customer records run there by default.

Who should perform sanity testing — QA or the developer who made the fix?

Either can, but the scope should be reviewed by someone who did not write the fix. Authors reliably under-scope their own blast radius — not from carelessness, but because they test the mental model they already had.

What if smoke passes but the build is obviously broken for testers?

That is a suite design gap and the most valuable feedback you can get. Find the smallest check that would have caught it, add it, and remove your least useful existing check to stay inside budget.

CTA — turn recurring sanity checks into owned cases

Sanity work generates more throwaway knowledge than any other QA activity. Use QA Workflow Assistant to convert the checks you keep repeating after fixes into structured, reviewable cases, then decide deliberately which graduate into the smoke or regression packs. Plan limits are on Pricing; pipeline setup lives in Docs.