QA Engineer Skills 2026QA-2026gRPC Fundamentals

gRPC Fundamentals

gRPC uses Protocol Buffers (protobuf) for schema definition and HTTP/2 for transport. It is common in microservice architectures where services need high-performance, type-safe communication. As a QA engineer, you may not test gRPC as frequently as REST, but understanding it is increasingly important.


How gRPC Differs from REST

Aspect REST gRPC
Protocol HTTP/1.1 or HTTP/2 HTTP/2 only
Data format JSON (text) Protocol Buffers (binary)
Schema Optional (OpenAPI) Required (.proto files)
Code generation Optional Built-in (generates client/server code)
Streaming Not native Native (server, client, bidirectional)
Browser support Native Requires gRPC-Web proxy
Error codes HTTP status codes gRPC status codes (own system)

Protocol Buffers

gRPC services are defined in .proto files:

syntax = "proto3";

package user;

service UserService {
    rpc GetUser(GetUserRequest) returns (UserResponse);
    rpc ListUsers(ListUsersRequest) returns (ListUsersResponse);
    rpc CreateUser(CreateUserRequest) returns (UserResponse);
    rpc UpdateUser(UpdateUserRequest) returns (UserResponse);
    rpc DeleteUser(DeleteUserRequest) returns (Empty);
}

message GetUserRequest {
    string id = 1;
}

message UserResponse {
    string id = 1;
    string name = 2;
    string email = 3;
    string role = 4;
    string created_at = 5;
}

message ListUsersRequest {
    int32 page = 1;
    int32 per_page = 2;
}

message ListUsersResponse {
    repeated UserResponse users = 1;
    int32 total = 2;
}

The .proto file is the contract. Both client and server generate code from it, ensuring type safety.


Exploring with grpcurl

grpcurl is like curl for gRPC — essential for manual exploration and debugging.

# List available services
grpcurl -plaintext localhost:50051 list

# List methods in a service
grpcurl -plaintext localhost:50051 list user.UserService

# Describe a method
grpcurl -plaintext localhost:50051 describe user.UserService.GetUser

# Call a method
grpcurl -plaintext -d '{"id": "123"}' localhost:50051 user.UserService/GetUser

# Call with headers (metadata)
grpcurl -plaintext \
    -H "Authorization: Bearer token123" \
    -d '{"id": "123"}' \
    localhost:50051 user.UserService/GetUser

# Call without TLS (-plaintext) for local development
# Call with TLS for staging/production (omit -plaintext)
grpcurl -d '{"id": "123"}' api.staging.example.com:443 user.UserService/GetUser

Testing gRPC with Python

import grpc
import user_pb2
import user_pb2_grpc

@pytest.fixture(scope="session")
def grpc_channel():
    channel = grpc.insecure_channel("localhost:50051")
    yield channel
    channel.close()

@pytest.fixture
def user_service(grpc_channel):
    return user_pb2_grpc.UserServiceStub(grpc_channel)

def test_get_user(user_service):
    request = user_pb2.GetUserRequest(id="123")
    response = user_service.GetUser(request)
    assert response.name == "Alice"
    assert response.email == "alice@test.com"

def test_get_nonexistent_user(user_service):
    request = user_pb2.GetUserRequest(id="nonexistent")
    with pytest.raises(grpc.RpcError) as exc_info:
        user_service.GetUser(request)
    assert exc_info.value.code() == grpc.StatusCode.NOT_FOUND

def test_create_user(user_service):
    request = user_pb2.CreateUserRequest(
        name="New User",
        email="new@test.com",
        role="viewer"
    )
    response = user_service.CreateUser(request)
    assert response.id != ""
    assert response.name == "New User"

gRPC Status Codes

gRPC uses its own status code system, not HTTP codes:

gRPC Code Meaning REST Equivalent
OK Success 200
INVALID_ARGUMENT Client sent bad data 400
NOT_FOUND Resource does not exist 404
ALREADY_EXISTS Duplicate creation 409
PERMISSION_DENIED Insufficient permissions 403
UNAUTHENTICATED Missing or invalid auth 401
RESOURCE_EXHAUSTED Rate limit or quota 429
INTERNAL Server error 500
UNAVAILABLE Service is down 503
DEADLINE_EXCEEDED Request timed out 504
UNIMPLEMENTED Method not implemented 501

Streaming

gRPC supports four communication patterns:

Pattern Description Use Case
Unary Client sends one request, server sends one response Standard CRUD
Server streaming Client sends one request, server sends stream of responses Live feed, log tailing
Client streaming Client sends stream of requests, server sends one response File upload, batch processing
Bidirectional Both sides send streams simultaneously Chat, real-time collaboration

Testing Server Streaming

def test_server_streaming(user_service):
    """Server streams all users matching a query."""
    request = user_pb2.ListUsersRequest(page=1, per_page=100)
    users = []
    for response in user_service.StreamUsers(request):
        users.append(response)
    assert len(users) > 0
    assert all(hasattr(u, "name") for u in users)

Deadline/Timeout Testing

gRPC has built-in deadline propagation — a client can set a deadline, and if the server does not respond in time, the call fails.

def test_deadline_exceeded(user_service):
    """Request with very short deadline should fail."""
    request = user_pb2.GetUserRequest(id="123")
    with pytest.raises(grpc.RpcError) as exc_info:
        # 1 microsecond deadline — guaranteed to fail
        user_service.GetUser(request, timeout=0.000001)
    assert exc_info.value.code() == grpc.StatusCode.DEADLINE_EXCEEDED

Practical Exercise

  1. Install grpcurl and explore a gRPC service (use a public demo or set up a local one)
  2. List available services and methods
  3. Make a unary call and inspect the response
  4. Write Python tests for a gRPC service: success case, not found, invalid argument
  5. Test deadline handling with a very short timeout

Key Takeaways

  • gRPC uses Protocol Buffers (binary, typed) instead of JSON (text, untyped)
  • grpcurl is the essential tool for manual gRPC exploration
  • gRPC has its own status code system — learn the mappings to HTTP codes
  • Test streaming (server, client, bidirectional) when the service supports it
  • Deadline propagation is built-in — test timeout behavior
  • The .proto file is the source of truth for the API contract