37 / 65 · 14 API Testing Fundamentals · Error Handling and Environment Management← prev⊞ allnext →☰ Read as one page
5.6Environment Parameterization
Your test suite must run against any environment with a single configuration change.
# conftest.py
import os
import pytest
@pytest.fixture(scope="session")
def base_url():
return os.environ.get("API_BASE_URL", "http://localhost:3000/api/v1")
# Run against different environments
API_BASE_URL=http://localhost:3000/api/v1 pytest tests/api/
API_BASE_URL=https://api.staging.example.com/v1 pytest tests/api/
API_BASE_URL=https://api.example.com/v1 pytest tests/api/ -m "readonly"
Best Practices
| Practice | Why |
|---|---|
| Environment variables for secrets | Never commit tokens to source control |
| Default to localhost | Tests run without configuration out of the box |
| Tag destructive tests | Exclude create/modify tests from production runs |
| Use .env files for local development | Keep local config out of command line |
| Different credentials per environment | Staging admin != production admin |
Marking Tests for Environment Safety
@pytest.mark.readonly
def test_list_users(api):
"""Safe to run against production — only reads data."""
r = api.get("/users")
assert r.status_code == 200
@pytest.mark.destructive
def test_delete_user(api, create_user):
"""Not safe for production — modifies data."""
user = create_user()
r = api.delete(f"/users/{user['id']}")
assert r.status_code == 204
# pytest.ini
[pytest]
markers =
readonly: Tests that only read data (safe for production)
destructive: Tests that create, modify, or delete data
smoke: Quick health check tests