Skip to content

Usage

Assert against your SLO

Drive the app through instrumented_client, then assert on the metrics fixture:

def test_home_meets_slo(instrumented_client, metrics):
    instrumented_client.get("/")
    metrics.assert_p99_below(1.0, handler="/")
    metrics.assert_no_server_errors()

Declare the SLO on the test

The metrics marker checks the budget after the test body runs:

@pytest.mark.metrics(p99_below=1.0, min_requests=3, no_errors=True)
def test_route_within_budget(instrumented_client):
    for _ in range(3):
        instrumented_client.get("/")

Spend an error budget

Allow a ratio of failures instead of demanding zero:

@pytest.mark.metrics(handler="/checkout", max_error_rate=0.01, max_4xx_rate=0.05)
def test_checkout_stays_in_budget(instrumented_client):
    for _ in range(100):
        instrumented_client.post("/checkout")
    # passes while 5xx <= 1% and 4xx <= 5% of requests

Assert on your own metrics

Declare a metric the ordinary way (a module-level Counter on the default registry) and assert without any wiring:

# in your app
from prometheus_client import Counter
CACHE_HITS = Counter("cache_hits", "served from cache", ["region"])

# in your test
def test_cache_is_used(instrumented_client, metrics):
    instrumented_client.get("/items/1")
    metrics.assert_metric("cache_hits_total", at_least=1)          # this test's delta
    metrics.assert_metric("queue_depth", delta=False, at_most=10)  # gauge: absolute

labels is a subset filter (omit it to sum every series). Because the app's global registry is shared across tests, counters report this test's delta by default; pass delta=False for a gauge whose current value you want as-is.