Testing your API

Build a test module, override a provider with a fake, and assert against real routing.

Bustan 0.0.2 ships testing utilities that build a real application from a real module graph, with providers you choose to replace. No mocking of the framework.

You should have completed the first tutorial.

A first test#

# tests/test_tasks.py
from bustan.testing import TestHarness
from app.tasks.module import TaskModule

async def test_creates_a_task():
    async with TestHarness(TaskModule) as harness:
        response = await harness.post("/tasks/", json={"title": "write docs"})

        assert response.status_code == 200
        assert response.json() == {"id": 1}

TestHarness builds the module graph exactly as production does — same resolution, same validation, same routing.

Override a provider#

Replace a real dependency with a fake without touching the module:

class FakeTaskService:
    def __init__(self) -> None:
        self.added: list[str] = []

    def add(self, title: str) -> int:
        self.added.append(title)
        return 99

    def all(self) -> dict[int, str]:
        return {}

async def test_delegates_to_the_service():
    async with TestHarness(TaskModule).override(TaskService, FakeTaskService()) as harness:
        await harness.post("/tasks/", json={"title": "x"})

        service = harness.get_provider(TaskService)
        assert service.added == ["x"]

The override is checked against the real type at build time — replacing a provider with something that does not satisfy it fails the test rather than failing mysteriously later.

Test a whole application#

from app.main import AppModule

async def test_health():
    async with TestHarness(AppModule) as harness:
        assert (await harness.get("/health")).status_code == 200

What the harness deliberately does not do#

  • It does not skip guards or interceptors. If a route is protected, your test authenticates or it gets a 401.
  • It does not relax validation.

Both are tempting and both would make tests pass that production would fail.

Next#

  • Add a guard, then write a test that authenticates past it — see the how-to guides