Smoke Testing
Smoke testing is a critical validation step that confirms an application's core functionalities are working after a build, deployment, or infrastructure change. It's quick, targeted, and aims to catch major issues early that would make the application "unusable."
What is a Smoke Test?
A smoke test focuses on:
- Verifying availability of core endpoints
- Ensuring the authentication mechanism works
- Receiving successful responses from backend services
- Connecting to the database or queues (if critical to the app)
It does not replace unit, integration, or end-to-end tests. Instead, it acts as a "gatekeeper" before deeper validation.
Best Practices
- Runs first after every deployment or restart
- Executes in under 1 minute — lightweight, fast validation
- No dependency on specific data — works without test fixtures
- Clear failure logs — each failure must be clearly visible with status and endpoint
- Reusable and configurable — e.g., via environment variables
Tools and Techniques
| Tool | Description |
|---|---|
curl, httpie | Simple HTTP checks from CLI |
Python + requests | Custom smoke logic in Python scripts |
| Azure DevOps, GitHub Actions | Integrate smoke stage into CI/CD pipeline |
| Retries | Use exponential backoff for services with startup delays |
Examples of Smoke Test Implementations
Bash script using curl
#!/bin/bash
set -e
BASE_URL="${1:-https://myapp.example.com}"
AUTH_HEADER="Authorization: Bearer ${SMOKE_TEST_TOKEN:-test-token}"
check() {
local endpoint=$1
echo -n "Checking $endpoint... "
status=$(curl -s -o /dev/null -w "%{http_code}" -H "$AUTH_HEADER" "$BASE_URL$endpoint")
if [ "$status" -eq 200 ]; then
echo "✅ OK"
else
echo "❌ Failed with status $status"
exit 1
fi
}
check "/"
check "/api/health"
check "/api/profile"
echo "🎉 Smoke Test Passed"
Python script using requests
import requests, sys, os
BASE_URL = sys.argv[1] if len(sys.argv) > 1 else "https://myapp.example.com"
TOKEN = os.environ.get("SMOKE_TEST_TOKEN", "test-token")
endpoints = ["/", "/api/health", "/api/profile"]
headers = {"Authorization": f"Bearer {TOKEN}"}
for endpoint in endpoints:
print(f"Checking {endpoint}...", end=" ")
try:
r = requests.get(f"{BASE_URL}{endpoint}", headers=headers)
if r.status_code == 200:
print("✅ OK")
else:
print(f"❌ Failed ({r.status_code})")
sys.exit(1)
except Exception as e:
print(f"❌ Error: {e}")
sys.exit(1)
print("🎉 All smoke tests passed.")
Optional Features
Retry Logic
Add retry mechanisms (e.g., until in Bash, time.sleep() & for attempt in range(n) in Python) to allow the app time to start properly.
Basic Auth / Token auth
Use headers:
-H "Authorization: Bearer $TOKEN"
or:
-u "user:password"
Dry Run Mode
Add a --dry-run flag to print endpoints without making requests. Useful for environment debugging.
Pipeline Integration (e.g., Azure DevOps)
- script: |
chmod +x smoke_test.sh
./smoke_test.sh https://myapp.example.com
env:
SMOKE_TEST_TOKEN: $(mySmokeToken)
displayName: "Run Smoke Test"
or:
- script: |
python3 smoke_test.py https://myapp.example.com
env:
SMOKE_TEST_TOKEN: $(mySmokeToken)
displayName: "Run Python Smoke Test"
What a Smoke Test Is Not
- It doesn’t perform logic validation (business rules)
- It doesn’t check performance or concurrency
- It doesn’t require specific data (fixtures)
- It doesn’t replace E2E or integration tests
Action Flow
- If it passes, proceed to the next stage.
- If it fails, rollback or investigate
Avoid hardcoding sensitive information in scripts — use environment variables or secret injection mechanisms (e.g., Azure Key Vault references).
Smoke testing should be lightweight enough to always run, but critical enough to stop everything when it fails.
