Production engineering guide for automation testing strategies covering patterns, implementation strategies, and operational best practices.
Automation testing strategies define how automated tests are designed, executed, maintained, and integrated into software delivery pipelines. They determine when and how fast feedback is delivered, and how deeply failures are diagnosed. This page covers the practices, patterns, and tradeoffs for building and operating automated testing at scale—focusing on what engineers do, not just what tools are available.
Choosing the right set of tests requires balancing speed, reliability, and depth. The most effective strategies use multiple layers of testing, each with distinct goals and execution patterns.
Unit tests verify individual functions, classes, or components in isolation. They run quickly and require minimal setup.
pytest for Python projects. A test file test_calculator.py includes: def test_add_positive_numbers():
assert add(2, 3) == 5
def test_add_negative_numbers():
assert add(-1, -1) == -2
pytest -v --cov=src --cov-report=html.--cov-report=html flag generates a htmlcov/ directory with color-coded coverage reports, useful for tracking test debt.unittest.mock.patch to isolate dependencies: from unittest.mock import patch
@patch("requests.get")
def test_fetch_user(mock_get):
mock_get.return_value.json.return_value = {"id": 1, "name": "Alice"}
user = fetch_user(1)
assert user["name"] == "Alice"
mock_get.assert_called_once_with("https://api.example.com/users/1")
Integration tests verify interactions between components, often involving real services.
docker-compose up -d to start services: database, message broker, API server.curl to validate API endpoints: curl -X POST http://localhost:8080/users \
-H "Content-Type: application/json" \
-d '{"name": "Bob", "email": "[email protected]"}'
curl -s http://localhost:8080/users/1 | jq .
# Expected:
# {
# "id": 1,
# "name": "Bob",
# "email": "[email protected]"
# }
docker-compose fails to start the database container due to a missing volume. The test passes locally but fails in CI.pg_dump and psql to manage database state: pg_dump -U postgres -h localhost -d testdb -f /tmp/initial.dump
psql -U postgres -h localhost -d testdb -f /tmp/initial.dump
tearDown in test fixtures to drop and recreate test databases.System tests validate the complete application stack under realistic conditions.
kubectl apply -f manifests/ to a Kubernetes cluster.kubectl get pods -o wide to verify all components are running.curl and jq pipelines: curl -s http://api.example.com/v1/orders \
| jq '.[] | select(.status == "pending") | .id'
kubectl logs <pod-name> --tail=50.kustomize to manage environment-specific configurations: # kustomization.yaml
resources:
- base
patchesStrategicMerge:
- configmap.yaml
vars:
- name: ENV
value: production
objref:
kind: ConfigMap
name: app-config
Automated testing strategies must define how and when tests run. The choice of orchestration affects speed, reliability, and visibility.
A typical CI pipeline uses git-triggered workflows with GitHub Actions, GitLab CI, or CircleCI.
.github/workflows/test.yml: name: Run Tests
on: [push, pull_request]
jobs:
test-unit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- run: pip install -r requirements.txt
- run: pytest -v --cov=src --cov-report=xml
- uses: actions/upload-artifact@v3
with:
name: test-results
path: |
htmlcov/
coverage.xml
if-no-files-found: ignore
test-integration:
needs: test-unit
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- run: docker-compose up -d --build
- run: sleep 10 # Wait for services to start
- run: curl -f http://localhost:8080/health
- run: pytest tests/integration/
- run: docker-compose down
curl -f fails but the job continues. The curl -f command does not exit with a non-zero code on HTTP 4xx or 5xx. Use curl -f -s to suppress output and make the failure visible.needs: test-unit but the test-integration job does not wait for test-unit to complete. Use needs: [test-unit] and strategy: matrix to run integration tests in parallel.Parallelize tests across multiple machines or containers.
pytest-xdist to run tests in parallel: pytest -n 4 --dist=loadgroup --tx=ssh://user@worker1 --tx=ssh://user@worker2
--dist=loadgroup flag groups related tests together to minimize communication overhead.--dist=loadfile to load test files in order, ensuring dependencies are met.--max-worker-restart=3 to restart workers after three test runs, preventing memory leaks.Test environments must be reproducible and consistent.
docker-compose with docker-compose.override.yml to define environment-specific settings: # docker-compose.override.yml
services:
web:
environment:
- ENV=staging
- LOG_LEVEL=info
ports:
- "8080:8080"
db:
environment:
- POSTGRES_DB=staging
- POSTGRES_USER=staging
- POSTGRES_PASSWORD=staging123
docker-compose up -d --build in CI to bring up the full stack.docker-compose down --volumes to clean up test data.docker-compose file uses build: ., but the Dockerfile is in a ./services/web directory. The build context is wrong, and the image is built with the wrong code.docker-compose exec web python manage.py migrate to run database migrations on the test environment.Feedback is only useful when it is actionable.
--junitxml=results.xml in pytest. - uses: actions/upload-artifact@v3
with:
name: test-results
path: |
results.xml
htmlcov/
logs/
jq to extract relevant data from test reports: jq -r '.testsuite | .testcase | .[] | select(.name | contains("login")) | .name' results.xml
pytest generates results.xml, but the CI tool expects junit.xml. The test summary is missing from the dashboard.When a test fails, engineers must diagnose the cause quickly.
kubectl describe pod <pod-name> to get the state of a failing test pod. kubectl logs api-7b8d5c9f45 --all-containers --tail=100
journalctl to inspect systemd services: journalctl -u myapp.service -n 100 --since "2023-10-05 10:00:00"
set -eux in shell scripts to catch errors: #!/bin/bash
set -eux
docker-compose up -d
sleep 10
curl -f http://localhost:8080/health
pytest tests/
Flaky tests fail intermittently without a root cause.
pytest --maxfail=2 --reruns=3 to retry tests up to three times.pytest-rerunfailures to automatically retry failed tests: # pytest.ini
[tool:pytest]
addopts = --reruns 3 --reruns-delay 2
--reruns-delay 2 to wait two seconds between retries, allowing time for services to recover.--reruns 3 and --reruns-delay 2 to handle flaky test cases.Tests must evolve with the codebase.
git to track test changes: git commit -m "test: add validation for user creation in API"
git push origin main
tests/README.md with setup instructions: # Running Tests
## Prerequisites
- Python 3.10
- Docker and docker-compose
## Setup
1. Start services: `docker-compose up -d`
2. Run unit tests: `pytest -v`
3. Run integration tests: `pytest tests/integration/`
pytest.mark.skipif to conditionally skip tests: import pytest
import os
@pytest.mark.skipif(os.getenv("CI") is None, reason="Only run in CI")
def test_in_ci_only():
# ...
pytest.mark.env to tag tests by environment: @pytest.mark.env("staging")
def test_staging_specific_behavior():
# ...
pip install . installs the package but not the test files. Use MANIFEST.in to include test files: include tests/*.py
include tests/data/*.json
recursive-include tests/data *.csv *.json
Deploy a new version to a subset of users and validate it with automated tests.
kubectl rollout canary: kubectl rollout canary deployment/api --set-image=api=example.com/api:v2.1
curl -f http://api.example.com/health
curl -s http://api.example.com/version | jq -r '.version'
Deploy a new version to a parallel environment (green) and switch traffic after validation.
kubectl to create a green deployment: kubectl apply -f manifests/green/
kubectl rollout status deployment/api-green
curl -f http://api-green.example.com/health
curl -s http://api-green.example.com/users | jq '. | length'
kubectl patch service/api: kubectl patch service/api -p '{"spec":{"selector":{"app":"api-green"}}}'
pg_dump to seed the green database before switching.Treat deployment as part of the test suite.
kubectl apply to deploy a new version, then run a test suite that validates the deployment. kubectl apply -f manifests/production/
sleep 30
pytest tests/deployment/
kubectl rollout undo deployment/api to roll back on failure.ab (Apache Bench) to measure response times: ab -n 1000 -c 50 http://api.example.com/users
This page was rewritten on 18 October 2026. It replaced a templated version that was not specific to its own title. How these pages are written and checked. If anything here is wrong, tell us at [email protected] and we will correct it.
We use cookies for analytics (Google Analytics) and advertising (Google AdSense) to improve your experience and support free content. Privacy Policy