Docs Tester DSL Migration: pytest/httpx

Migrating from pytest + httpx to the Mockarty Tester

pytest + httpx is the canonical Python HTTP test stack. The Mockarty
Tester DSL is a drop-in replacement when you want:

  • Multi-protocol reach in one DSL (HTTP, gRPC, GraphQL, Kafka,
    RabbitMQ, SSE, WebSocket, SOAP, DB)
  • Variable interpolation across chain steps with {{token}} syntax
  • TCM external-run upload in one call

At a glance

pytest + httpx Mockarty Tester (Python)
httpx.get(url) t.http().get(url)
resp.status_code == 200 .expect_status(200)
assert resp.json()["name"] == "Alice" .expect_json_path("$.name", "Alice")
assert "abc" in resp.text .expect_body_contains("abc")
resp.headers["X-Foo"] == "y" .expect_header("X-Foo", "y")
httpx.post(url, json={...}) .post(url).json({...})
httpx.Client(headers={...}) Tester(default_headers={...})
Reusing token = resp.json()["token"] .extract("$.token", "token")
Then headers={"Authorization": f"Bearer {token}"} .header("Authorization", "Bearer {{token}}")
Parametrize via fixture Pre-populate via t.set_var(...)

Side-by-side example

pytest + httpx

import httpx
import pytest


def test_login_and_me():
    base = "http://localhost:8080"
    with httpx.Client(base_url=base) as c:
        login = c.post("/login", json={"user": "alice"})
        assert login.status_code == 200
        token = login.json()["token"]

        me = c.get("/me", headers={"Authorization": f"Bearer {token}"})
        assert me.status_code == 200
        assert me.json()["user"] == "alice"

Mockarty Tester

from mockarty.tester import Tester


def test_login_and_me():
    with Tester(base_url="http://localhost:8080") as t:
        (t.http().post("/login")
            .json({"user": "alice"})
            .expect_status(200)
            .extract("$.token", "token"))
        (t.http().get("/me")
            .header("Authorization", "Bearer {{token}}")
            .expect_status(200)
            .expect_json_path("$.user", "alice"))
        assert t.ok(), t.errors()

Why migrate

  • Vocabulary stays the same across Go / Python / Java. A QA team
    writing Tester chains in Python can hand the source to a Go-shop
    to maintain — the chain reads identically.
  • Allure / TCM out of the box. The Tester captures every step
    with timing + status + protocol metadata. to_report_kwargs(t, ...)
    maps the result to client.external_runs.report(**) for TCM upload.
  • No HTTP boilerplate for chaining. Tester’s {{var}} template
    handles cross-step plumbing without f-string concatenation.

Reporting back to Mockarty TCM

from mockarty import MockartyClient
from mockarty.tester import Tester, to_report_kwargs

with MockartyClient(base_url="http://...", api_key="...", namespace="qa") as client:
    with Tester(base_url="http://localhost:8080") as t:
        # ... chain
        client.external_runs.report(
            **to_report_kwargs(t, case_name="Login flow", auto_create=True),
        )

The pytest test → IR → TCM external run pipeline closes the loop:
run any pytest, ship the result via the SDK, see it on the
Mockarty admin page next to native test-plan runs.

Coexistence with pytest

The Tester is NOT a pytest replacement — it’s a fluent API for
writing the HTTP / RPC / message-bus pieces of your test. Keep
@pytest.fixture, pytest -k, pytest-xdist etc. — they all work
unchanged. Tester replaces only the httpx-shaped assertions inside
the test body.

import pytest
from mockarty.tester import Tester


@pytest.fixture
def t():
    with Tester(base_url="http://localhost:8080") as t:
        yield t


@pytest.mark.parametrize("user_id", [1, 2, 3])
def test_user_visible(t, user_id):
    t.http().get(f"/users/{user_id}").expect_status(200)
    assert t.ok(), t.errors()