Skip to content

smoke test

A smoke test is a small, fast set of checks that runs after a build or a deploy to confirm a system’s most critical paths still work. If a smoke test fails, the build does not move on to the rest of the test suite and the deploy is rolled back before users see it. If it passes, the team has cheap confidence that deeper work further up the test pyramid is worth the time, and the full gate looks like this:

Left to right flowchart. A white Build or deploy box feeds a teal Smoke test diamond. A pass arrow leads to Full test suite then green Release. A fail arrow leads to coral Halt and Roll back.
The smoke test is the gate that decides whether the rest of the pipeline runs.

The phrase has a contested origin. The most-cited software citation, Kaner, Bach, and Pettichord’s Lessons Learned in Software Testing, traces it to electronics hardware testing, where an engineer powered on a new board and watched for smoke.

The plumbing meaning, in which smoke is pumped through pipes to find leaks, predates software and gets cited as well. Both carry the same spirit: a quick “does this even turn on?” check before deeper validation.

How It Shows Up in Practice

A Python developer typically meets smoke tests in two places. The first is a CI job that runs immediately after every build. The second is a post-deploy job that runs against a staging or production environment right after a release.

The CI form is usually a handful of tests pulled from an existing pytest suite, tagged with a marker so the runner can select them on demand:

Language: Python
import pytest

@pytest.mark.smoke
def test_home_page_renders(client):
    response = client.get("/")
    assert response.status_code == 200

@pytest.mark.smoke
def test_user_can_log_in(client):
    response = client.post("/login", json={"user": "u", "password": "p"})
    assert response.status_code == 200

A GitHub Actions job then runs pytest -m smoke --tb=short ahead of the full suite. If those two tests fail, the rest of the suite never starts. The same pattern works in GitLab CI, Jenkins, or any other runner that can scope a job to a marker.

The post-deploy form is often a small standalone script that hits the deployed service and exits non-zero on the first broken critical path. It can be written with only the standard library:

Language: Python
import json
import sys

# Each check stands in for a real production probe (an HTTP request,
# a database query, a queue ping). The runner cares only that every
# check returns a truthy value and that the first failure is loud.

def homepage_reachable():
    response_status = 200
    return response_status == 200

def critical_api_responds():
    payload = json.loads('{"status": "ok"}')
    return payload.get("status") == "ok"

def database_migrations_applied():
    expected, actual = 7, 7
    return expected == actual

CHECKS = [
    ("homepage reachable", homepage_reachable),
    ("critical api responds", critical_api_responds),
    ("database migrations applied", database_migrations_applied),
]

for name, check in CHECKS:
    if check():
        print(f"ok    {name}")
    else:
        print(f"FAIL  {name}", file=sys.stderr)
        sys.exit(1)
Language: Program Output
ok    homepage reachable
ok    critical api responds
ok    database migrations applied

In a real deployment each function would call urllib.request.urlopen against /healthz, hit the login endpoint, or query a migrations table. The shape stays the same: a small list of named checks, fail-fast on the first failure, finish in seconds. Teams that practice behavior-driven development often pick the smoke-suite candidates straight from their highest-value Given/When/Then scenarios.

Common Pitfalls

Smoke tests fail in three recurring ways that teams keep rediscovering.

  • Bloat. Smoke suites accrete tests until they take ten minutes to run and lose their fast-feedback value. The discipline is deletion. If a check does not gate the rest of the pipeline, it belongs in the full regression suite, not the smoke suite.
  • Flakiness. A flaky test in the smoke suite is worse than no smoke suite at all, because it trains the team to retry-and-ignore the gate. A check that fails for environmental reasons more than once a month should be moved out or fixed.
  • Smoke-as-coverage. A green smoke run means “this build is not obviously broken,” not “this build works.” Teams sometimes ship on green smoke and skip the full suite, which converts the smoke test from a fast filter into a false promise.

A related vocabulary trap is the word sanity test. The ISTQB Glossary treats smoke and sanity as synonyms, but most teams in practice use smoke for a broad, shallow check on a fresh build and sanity for a narrow, deeper check after a small change. Pick one term per team and write down what it means in your repository’s contributing guide.

Tutorial

Continuous Integration With Python: An Introduction

In this Python tutorial, you'll learn the core concepts behind Continuous Integration (CI) and why they are essential for modern software engineering teams. Find out how to how set up Continuous Integration for your Python project to automatically create environments, install dependencies, and run tests.

intermediate best-practices devops testing

For additional information on related topics, take a look at the following resources:


By Martin Breuss • Updated May 29, 2026 • Reviewed by Luke Lee