Testing¶
fastgrpc3.testing.TestClient starts an app on 127.0.0.1 and a free port, and opens a
channel to it. It is a real server, so tests go through the same encoding, validation,
hooks and errors as production.
import pytest
from fastgrpc3 import GrpcError, StatusCode
from fastgrpc3.testing import TestClient
from myapp.main import app
from myapp.client import OrdersClient
from myapp.deps import get_repository
@pytest.fixture
async def orders():
app.dependency_overrides[get_repository] = lambda: FakeRepository()
try:
async with TestClient(app) as tc:
yield tc.client(OrdersClient)
finally:
app.dependency_overrides.clear()
async def test_unknown_order(orders: OrdersClient) -> None:
with pytest.raises(GrpcError) as raised:
await orders.get_order(GetOrderRequest(order_number="?"))
assert raised.value.code == StatusCode.NOT_FOUND
- The app must use
tls=Insecure();TestClientreplaces its address. tc.channelis theChannel, for calls without a client class (the rawgrpc.aiochannel istc.channel.grpc_channel).TestClient(app, default_timeout=10.0)sets the channel's timeout.- Overrides are read when the app starts: set them before
async with TestClient(app).
With pytest, use pytest-asyncio in auto mode:
pyproject.toml
[tool.pytest.ini_options]
asyncio_mode = "auto"
asyncio_default_fixture_loop_scope = "function"
Handlers stay plain functions: the decorators return them unchanged, so a unit test can also call one directly with a request and fake dependencies.
examples/tests/test_bookstore.py tests every RPC of the example service this way.