Lesson 24 / 25
Testing gRPC Services
Unit, in-process and contract tests.
Test at several levels
Unit-test servicer methods directly by calling them with request messages and a fake context. For realistic tests without networking, run the server in-process (grpc-go's bufconn, in-process channels in Java and .NET, or a server on a random local port in Python) and call it through a real client stub, which exercises interceptors and serialisation. Contract safety comes from buf breaking and generated clients; add end-to-end tests for critical flows, and test deadlines, cancellation and error codes, not only success paths.
An in-process test in Python
pytest sketch starting a server on a free local port.
import grpc, pytest
from concurrent import futures
@pytest.fixture
def stub():
server = grpc.server(futures.ThreadPoolExecutor(max_workers=2))
order_pb2_grpc.add_OrderServiceServicer_to_server(OrderService(repo=FakeRepo()), server)
port = server.add_insecure_port("localhost:0") # pick a free port
server.start()
with grpc.insecure_channel(f"localhost:{port}") as channel:
yield order_pb2_grpc.OrderServiceStub(channel)
server.stop(None)
def test_missing_order_returns_not_found(stub):
with pytest.raises(grpc.RpcError) as err:
stub.GetOrder(order_pb2.GetOrderRequest(id="nope"), timeout=1)
assert err.value.code() == grpc.StatusCode.NOT_FOUNDAssert on status codes
Tests that check the exact status code keep error behaviour stable for clients.
Quick check: Why run the server in-process for tests?
- It removes the need for proto files
- It makes protobuf optional
- It exercises real stubs, serialisation and interceptors without external networking
- It disables deadlines
Answer
It exercises real stubs, serialisation and interceptors without external networking — Realistic yet fast.