Smoke Testing
What it is
Section titled “What it is”A smoke test — also called build acceptance or a confidence check — is a shallow, broad check that a build is stable enough to test at all. It does not verify features deeply; it answers one question: is this build sane enough to hand to the testers?
The name comes from hardware: power on the board, and if it does not smoke, keep going.
build ──► SMOKE (a few minutes) ──► full test suite │ pass │ └ fail → stop the line └ deep verification continuesSmoke tests are wide but not deep: every major area gets touched, nothing gets a deep verification. They run first and fail fast, so an obviously broken build does not burn CI minutes or reach users.
When to use it / when to avoid it
Section titled “When to use it / when to avoid it”Use it for
- After every deployment or CI build, before the wider suite runs
- Confirming critical entry points respond (the login page loads, the health endpoint returns 200, the app boots)
- A cheap gate that stops a broken build before it wastes time or ships
Avoid it when
- You need confidence in one just-changed feature → use a sanity test
- You need to prove nothing else broke → use a regression test
- The whole suite is already small and fast — a separate smoke set adds nothing
Frameworks & tools
Section titled “Frameworks & tools”| Tool | Ecosystem | Notes |
|---|---|---|
| Playwright | Multi | Tag a @smoke subset and select it with --grep |
| Cypress | Node | Run only tagged specs with --env grepTags=@smoke |
| pytest | Python | @pytest.mark.smoke plus -m smoke |
| Postman / Newman | Multi | Replay a collection as a post-deploy check |
| Robot Framework | Python | Keyword-driven smoke suite selected by tags |
| curl / shell | Multi | Minimal HTTP health checks in a pipeline step |
| Go testing | Go | go test ./... -run Smoke |
| JUnit 5 | Java/JVM | @Tag("smoke") with Maven Surefire groups |
| xUnit / NUnit | .NET | [Trait] / [Category] filtered by dotnet test |
| k6 / Vegeta | Multi | A minute of baseline traffic as a load smoke test |
Quick setup
Section titled “Quick setup”npm install -D @playwright/testnpx playwright test --grep @smokepip install pytest httpxpytest -m smoke -qgo test ./... -run Smoke -count=1<!-- Maven: run only the smoke group --><plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <configuration> <groups>smoke</groups> </configuration></plugin>dotnet test --filter "Category=Smoke"Example
Section titled “Example”import { test, expect } from '@playwright/test';
test('@smoke home page responds', async ({ page }) => { const res = await page.goto('/'); expect(res?.status()).toBe(200); await expect(page.getByRole('heading', { level: 1 })).toBeVisible();});import httpximport pytest
@pytest.mark.smokedef test_health_endpoint(): response = httpx.get("http://localhost:8000/health") assert response.status_code == 200 assert response.json()["status"] == "ok"func TestSmokeHealth(t *testing.T) { resp, err := http.Get(baseURL + "/health") if err != nil { t.Fatalf("health request failed: %v", err) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { t.Fatalf("want 200, got %d", resp.StatusCode) }}import static org.junit.jupiter.api.Assertions.assertEquals;import java.net.URI;import java.net.http.*;import org.junit.jupiter.api.Tag;import org.junit.jupiter.api.Test;
class SmokeTest { @Test @Tag("smoke") void healthEndpointResponds() throws Exception { var client = HttpClient.newHttpClient(); var req = HttpRequest.newBuilder(URI.create(BASE_URL + "/health")).build(); var res = client.send(req, HttpResponse.BodyHandlers.ofString()); assertEquals(200, res.statusCode()); }}using System.Net;using System.Net.Http;using Xunit;
public class SmokeTests{ [Fact] [Trait("Category", "Smoke")] public async Task HealthEndpointResponds() { using var client = new HttpClient(); var res = await client.GetAsync($"{BaseUrl}/health"); Assert.Equal(HttpStatusCode.OK, res.StatusCode); }}Anti-patterns & best practices
Section titled “Anti-patterns & best practices”- Keep it short. Aim for minutes, not hours; a smoke suite that is slow stops being run.
- Cover breadth, not depth. One happy path per major area, no edge cases.
- Run it first. Put smoke in the earliest CI stage so a broken build stops the line.
- Assert on real signals. A 200 on the health endpoint, not merely “the process started”.
- Do not grow it into a regression suite. When smoke needs edge cases, that is a sanity or regression concern.
- Make failures obvious. A red smoke run should name the exact area that is down.
Self-assessment quiz
Section titled “Self-assessment quiz”Self-assessment quiz
Pick one answer per question, then press Check answers.