Prompt file imported from ADASK-B/gRPC.Agent.Template (
.github/prompts/grpc-test.prompt.md). Copyright stays with the author.
Generate integration tests for gRPC services:
Test Project Setup
Required NuGet packages:
Microsoft.AspNetCore.Mvc.TestingGrpc.Net.ClientGrpc.Tools(for proto compilation)- A test framework (xUnit, NUnit, or MSTest)
Reference the same .proto files as the server project with GrpcServices="Client" or GrpcServices="Both".
Test Infrastructure
public class GrpcTestFixture<TStartup> : IDisposable where TStartup : class
{
private readonly WebApplicationFactory<TStartup> _factory;
public GrpcChannel Channel { get; }
public GrpcTestFixture()
{
_factory = new WebApplicationFactory<TStartup>();
var client = _factory.CreateDefaultClient(new ResponseVersionHandler());
Channel = GrpcChannel.ForAddress(client.BaseAddress!, new GrpcChannelOptions
{
HttpClient = client
});
}
public void Dispose()
{
Channel.Dispose();
_factory.Dispose();
}
}
// Required to set HTTP/2 for the test client
public class ResponseVersionHandler : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, CancellationToken ct)
{
request.Version = new Version(2, 0);
var response = await base.SendAsync(request, ct);
response.Version = request.Version;
return response;
}
}
Test Patterns
Unary RPC Test
[Fact]
public async Task GetItem_ValidId_ReturnsItem()
{
var client = new MyService.MyServiceClient(Channel);
var reply = await client.GetItemAsync(new GetItemRequest { Id = "123" });
Assert.Equal("123", reply.Item.Id);
}
Error Handling Test
[Fact]
public async Task GetItem_EmptyId_ThrowsRpcException()
{
var client = new MyService.MyServiceClient(Channel);
var ex = await Assert.ThrowsAsync<RpcException>(
() => client.GetItemAsync(new GetItemRequest { Id = "" }));
Assert.Equal(StatusCode.InvalidArgument, ex.StatusCode);
}
Streaming RPC Test
[Fact]
public async Task ServerStream_ReturnsAllMessages()
{
var client = new MyService.MyServiceClient(Channel);
var messages = new List<ResponseMessage>();
using var call = client.ServerStreamMethod(new Request());
await foreach (var msg in call.ResponseStream.ReadAllAsync())
{
messages.Add(msg);
}
Assert.NotEmpty(messages);
}
Guidelines
- Test both success and error paths
- Verify correct gRPC status codes for error cases
- Test deadline/cancellation behavior
- Use unique test data to avoid conflicts
- Mock external dependencies using DI service overrides