gRPC Mocking
MockForge provides comprehensive gRPC service mocking with dynamic Protocol Buffer discovery, streaming support, and flexible service registration. This enables testing of gRPC-based microservices and APIs with realistic mock responses.
Overview
MockForge’s gRPC mocking system offers:
- Dynamic Proto Discovery: Automatically discovers and compiles
.proto
files from configurable directories - Flexible Service Registration: Register and mock any gRPC service without hardcoding
- Streaming Support: Full support for unary, server streaming, client streaming, and bidirectional streaming
- Reflection Support: Built-in gRPC reflection for service discovery and testing
- Template Integration: Use MockForge’s template system for dynamic response generation
- Advanced Data Synthesis: Intelligent mock data generation with deterministic seeding, relationship awareness, and RAG-driven domain knowledge
Quick Start
Basic gRPC Server
Start a gRPC mock server with default configuration:
# Start with default proto directory (proto/)
mockforge serve --grpc-port 50051
With Custom Proto Directory
# Specify custom proto directory
MOCKFORGE_PROTO_DIR=my-protos mockforge serve --grpc-port 50051
Complete Example
# Start MockForge with HTTP, WebSocket, and gRPC support
MOCKFORGE_RESPONSE_TEMPLATE_EXPAND=true \
MOCKFORGE_WS_REPLAY_FILE=examples/ws-demo.jsonl \
MOCKFORGE_PROTO_DIR=examples/grpc-protos \
mockforge serve \
--spec examples/openapi-demo.json \
--http-port 3000 \
--ws-port 3001 \
--grpc-port 50051 \
--admin --admin-port 8080
Proto File Setup
Directory Structure
MockForge automatically discovers .proto
files in a configurable directory:
your-project/
├── proto/ # Default proto directory
│ ├── user_service.proto # Will be discovered
│ ├── payment.proto # Will be discovered
│ └── subdir/
│ └── analytics.proto # Will be discovered (recursive)
└── examples/
└── grpc-protos/ # Custom proto directory
└── service.proto
Sample Proto File
syntax = "proto3";
package mockforge.user;
service UserService {
rpc GetUser(GetUserRequest) returns (UserResponse);
rpc ListUsers(ListUsersRequest) returns (stream UserResponse);
rpc CreateUser(stream CreateUserRequest) returns (UserResponse);
rpc Chat(stream ChatMessage) returns (stream ChatMessage);
}
message GetUserRequest {
string user_id = 1;
}
message UserResponse {
string user_id = 1;
string name = 2;
string email = 3;
int64 created_at = 4;
Status status = 5;
}
message ListUsersRequest {
int32 limit = 1;
string filter = 2;
}
message CreateUserRequest {
string name = 1;
string email = 2;
}
message ChatMessage {
string user_id = 1;
string content = 2;
int64 timestamp = 3;
}
enum Status {
UNKNOWN = 0;
ACTIVE = 1;
INACTIVE = 2;
SUSPENDED = 3;
}
Dynamic Response Generation
MockForge generates responses automatically based on your proto message schemas, with support for templates and custom logic.
Automatic Response Generation
For basic use cases, MockForge generates responses from proto schemas:
- Strings: Random realistic values
- Integers: Random numbers in appropriate ranges
- Timestamps: Current time or future dates
- Enums: Random valid enum values
- Messages: Nested objects with generated data
- Repeated fields: Arrays with multiple generated items
Template-Enhanced Responses
Use MockForge templates in proto comments for custom responses:
message UserResponse {
string user_id = 1; // {{uuid}}
string name = 2; // {{request.user_id == "123" ? "John Doe" : "Jane Smith"}}
string email = 3; // {{name | replace(" ", ".") | lower}}@example.com
int64 created_at = 4; // {{now}}
Status status = 5; // ACTIVE
}
Request Context Access
Access request data in templates:
message UserResponse {
string user_id = 1; // {{request.user_id}}
string requested_by = 2; // {{request.metadata.user_id}}
string message = 3; // User {{request.user_id}} was retrieved
}
Testing gRPC Services
Using gRPC CLI Tools
grpcurl (Recommended)
# Install grpcurl
go install github.com/fullstorydev/grpcurl/cmd/grpcurl@latest
# List available services
grpcurl -plaintext localhost:50051 list
# Call a unary method
grpcurl -plaintext -d '{"user_id": "123"}' \
localhost:50051 mockforge.user.UserService/GetUser
# Call a server streaming method
grpcurl -plaintext -d '{"limit": 5}' \
localhost:50051 mockforge.user.UserService/ListUsers
# Call a client streaming method
echo '{"name": "Alice", "email": "alice@example.com"}' | \
grpcurl -plaintext -d @ \
localhost:50051 mockforge.user.UserService/CreateUser
grpcui (Web Interface)
# Install grpcui
go install github.com/fullstorydev/grpcui/cmd/grpcui@latest
# Start web interface
grpcui -plaintext localhost:50051
# Open http://localhost:2633 in your browser
Programmatic Testing
Node.js with grpc-js
const grpc = require('@grpc/grpc-js');
const protoLoader = require('@grpc/proto-loader');
const packageDefinition = protoLoader.loadSync(
'proto/user_service.proto',
{
keepCase: true,
longs: String,
enums: String,
defaults: true,
oneofs: true
}
);
const protoDescriptor = grpc.loadPackageDefinition(packageDefinition);
const client = new protoDescriptor.mockforge.user.UserService(
'localhost:50051',
grpc.credentials.createInsecure()
);
// Unary call
client.GetUser({ user_id: '123' }, (error, response) => {
if (error) {
console.error('Error:', error);
} else {
console.log('Response:', response);
}
});
// Server streaming
const stream = client.ListUsers({ limit: 5 });
stream.on('data', (response) => {
console.log('User:', response);
});
stream.on('end', () => {
console.log('Stream ended');
});
Python with grpcio
import grpc
from user_service_pb2 import GetUserRequest
from user_service_pb2_grpc import UserServiceStub
channel = grpc.insecure_channel('localhost:50051')
stub = UserServiceStub(channel)
# Unary call
request = GetUserRequest(user_id='123')
response = stub.GetUser(request)
print(f"User: {response.name}, Email: {response.email}")
# Streaming
for user in stub.ListUsers(ListUsersRequest(limit=5)):
print(f"User: {user.name}")
Advanced Configuration
Custom Response Mappings
Create custom response logic by implementing service handlers:
#![allow(unused)] fn main() { use mockforge_grpc::{ServiceRegistry, ServiceImplementation}; use std::collections::HashMap; struct CustomUserService { user_data: HashMap<String, UserResponse>, } impl ServiceImplementation for CustomUserService { fn handle_unary(&self, method: &str, request: &[u8]) -> Vec<u8> { match method { "GetUser" => { let req: GetUserRequest = prost::Message::decode(request).unwrap(); let response = self.user_data.get(&req.user_id) .cloned() .unwrap_or_else(|| UserResponse { user_id: req.user_id, name: "Unknown User".to_string(), email: "unknown@example.com".to_string(), created_at: std::time::SystemTime::now() .duration_since(std::time::UNIX_EPOCH) .unwrap().as_secs() as i64, status: Status::Unknown as i32, }); let mut buf = Vec::new(); response.encode(&mut buf).unwrap(); buf } _ => Vec::new(), } } } }
Environment Variables
# Proto file configuration
MOCKFORGE_PROTO_DIR=proto/ # Directory containing .proto files
MOCKFORGE_GRPC_PORT=50051 # gRPC server port
# Service behavior
MOCKFORGE_GRPC_LATENCY_ENABLED=true # Enable response latency
MOCKFORGE_GRPC_LATENCY_MIN_MS=10 # Minimum latency
MOCKFORGE_GRPC_LATENCY_MAX_MS=100 # Maximum latency
# Reflection settings
MOCKFORGE_GRPC_REFLECTION_ENABLED=true # Enable gRPC reflection
Configuration File
grpc:
port: 50051
proto_dir: "proto/"
enable_reflection: true
latency:
enabled: true
min_ms: 10
max_ms: 100
services:
- name: "mockforge.user.UserService"
implementation: "dynamic"
- name: "custom.Service"
implementation: "custom_handler"
Streaming Support
MockForge supports all gRPC streaming patterns:
Unary (Request → Response)
rpc GetUser(GetUserRequest) returns (UserResponse);
Standard request-response pattern used for simple operations.
Server Streaming (Request → Stream of Responses)
rpc ListUsers(ListUsersRequest) returns (stream UserResponse);
Single request that returns multiple responses over time.
Client Streaming (Stream of Requests → Response)
rpc CreateUsers(stream CreateUserRequest) returns (UserSummary);
Multiple requests sent as a stream, single response returned.
Bidirectional Streaming (Stream ↔ Stream)
rpc Chat(stream ChatMessage) returns (stream ChatMessage);
Both client and server can send messages independently.
Error Handling
gRPC Status Codes
MockForge supports all standard gRPC status codes:
// In proto comments for custom error responses
rpc GetUser(GetUserRequest) returns (UserResponse);
// @error NOT_FOUND User not found
// @error INVALID_ARGUMENT Invalid user ID format
// @error INTERNAL Server error occurred
Custom Error Responses
#![allow(unused)] fn main() { // Custom error handling fn handle_unary(&self, method: &str, request: &[u8]) -> Result<Vec<u8>, tonic::Status> { match method { "GetUser" => { let req: GetUserRequest = prost::Message::decode(request)?; if !is_valid_user_id(&req.user_id) { return Err(tonic::Status::invalid_argument("Invalid user ID")); } match self.get_user(&req.user_id) { Some(user) => { let mut buf = Vec::new(); user.encode(&mut buf)?; Ok(buf) } None => Err(tonic::Status::not_found("User not found")), } } _ => Err(tonic::Status::unimplemented("Method not implemented")), } } }
Integration Patterns
Microservices Testing
# Start multiple gRPC services
MOCKFORGE_PROTO_DIR=user-proto mockforge serve --grpc-port 50051 &
MOCKFORGE_PROTO_DIR=payment-proto mockforge serve --grpc-port 50052 &
MOCKFORGE_PROTO_DIR=inventory-proto mockforge serve --grpc-port 50053 &
# Test service communication
grpcurl -plaintext localhost:50051 mockforge.user.UserService/GetUser \
-d '{"user_id": "123"}'
Load Testing
# Simple load test with hey
hey -n 1000 -c 10 \
grpcurl -plaintext -d '{"user_id": "123"}' \
localhost:50051 mockforge.user.UserService/GetUser
# Advanced load testing with ghz
ghz --insecure \
--proto proto/user_service.proto \
--call mockforge.user.UserService.GetUser \
--data '{"user_id": "123"}' \
--concurrency 10 \
--total 1000 \
localhost:50051
CI/CD Integration
# .github/workflows/test.yml
name: gRPC Tests
on: [push, pull_request]
jobs:
grpc-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Rust
uses: actions-rust-lang/setup-rust-toolchain@v1
- name: Start MockForge
run: |
cargo run --bin mockforge-cli -- serve --grpc-port 50051 &
sleep 5
- name: Run gRPC Tests
run: |
npm install -g grpcurl
grpcurl -plaintext localhost:50051 list
# Add your test commands here
Best Practices
Proto File Organization
- Clear Package Names: Use descriptive package names that reflect service domains
- Consistent Naming: Follow protobuf naming conventions
- Versioning: Include version information in package names when appropriate
- Documentation: Add comments to proto files for better API documentation
Service Design
- Appropriate Streaming: Choose the right streaming pattern for your use case
- Error Handling: Define clear error conditions and status codes
- Pagination: Implement pagination for large result sets
- Backwards Compatibility: Design for evolution and backwards compatibility
Testing Strategies
- Unit Tests: Test individual service methods
- Integration Tests: Test service interactions
- Load Tests: Verify performance under load
- Chaos Tests: Test failure scenarios and recovery
Performance Optimization
- Response Caching: Cache frequently requested data
- Connection Pooling: Reuse gRPC connections
- Async Processing: Use async operations for I/O bound tasks
- Memory Management: Monitor and optimize memory usage
Troubleshooting
Common Issues
Proto files not found: Check MOCKFORGE_PROTO_DIR
environment variable and directory permissions
Service not available: Verify proto compilation succeeded and service names match
Connection refused: Ensure gRPC port is accessible and not blocked by firewall
Template errors: Check template syntax and available context variables
Debug Commands
# Check proto compilation
cargo build --verbose
# List available services
grpcurl -plaintext localhost:50051 list
# Check service methods
grpcurl -plaintext localhost:50051 describe mockforge.user.UserService
# Test with verbose output
grpcurl -plaintext -v -d '{"user_id": "123"}' \
localhost:50051 mockforge.user.UserService/GetUser
Log Analysis
# View gRPC logs
tail -f mockforge.log | grep -i grpc
# Count requests by service
grep "grpc.*call" mockforge.log | cut -d' ' -f5 | sort | uniq -c
# Monitor errors
grep -i "grpc.*error" mockforge.log
For detailed implementation guides, see:
- Protocol Buffers - Working with .proto files
- Streaming - Advanced streaming patterns
- Advanced Data Synthesis - Intelligent data generation with RAG and validation