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