Condividi tramite


Testare i servizi gRPC in ASP.NET Core

Nota

Questa non è la versione più recente di questo articolo. Per la versione corrente, vedere la versione .NET 9 di questo articolo.

Avviso

Questa versione di ASP.NET Core non è più supportata. Per altre informazioni, vedere i criteri di supporto di .NET e .NET Core. Per la versione corrente, vedere la versione .NET 9 di questo articolo.

Importante

Queste informazioni si riferiscono a un prodotto non definitive che può essere modificato in modo sostanziale prima che venga rilasciato commercialmente. Microsoft non riconosce alcuna garanzia, espressa o implicita, in merito alle informazioni qui fornite.

Per la versione corrente, vedere la versione .NET 9 di questo articolo.

Da: James Newton-King

Il test è un aspetto importante della creazione di software stabile e gestibile. Questo articolo illustra come testare i servizi ASP.NET Core gRPC.

Esistono tre approcci comuni per testare i servizi gRPC:

  • Unit test: testare i servizi gRPC direttamente da una libreria di unit test.
  • Test di integrazione: l'app gRPC è ospitata in TestServer, un server di test in memoria dal Microsoft.AspNetCore.TestHost pacchetto. I servizi gRPC vengono testati chiamandoli usando un client gRPC da una libreria di unit test.
  • Test manuali: testare i server gRPC con chiamate ad hoc. Per informazioni su come usare gli strumenti della riga di comando e dell'interfaccia utente con i servizi gRPC, vedere Testare i servizi gRPC con gRPCurl e gRPCui in ASP.NET Core.

Negli unit test è coinvolto solo il servizio gRPC. Le dipendenze inserite nel servizio devono essere fittizie. Nei test di integrazione, il servizio gRPC e l'infrastruttura ausiliaria fanno parte del test. Sono inclusi l'avvio dell'app, l'inserimento delle dipendenze, il routing e l'autenticazione e l'autorizzazione.

Esempio di servizio testabile

Per illustrare i test del servizio, esaminare il servizio seguente nell'app di esempio.

Visualizzare o scaricare il codice di esempio (procedura per il download)

Restituisce TesterService i messaggi di saluto usando i quattro tipi di metodo di gRPC.

public class TesterService : Tester.TesterBase
{
    private readonly IGreeter _greeter;

    public TesterService(IGreeter greeter)
    {
        _greeter = greeter;
    }

    public override Task<HelloReply> SayHelloUnary(HelloRequest request,
        ServerCallContext context)
    {
        var message = _greeter.Greet(request.Name);
        return Task.FromResult(new HelloReply { Message = message });
    }

    public override async Task SayHelloServerStreaming(HelloRequest request,
        IServerStreamWriter<HelloReply> responseStream, ServerCallContext context)
    {
        var i = 0;
        while (!context.CancellationToken.IsCancellationRequested)
        {
            var message = _greeter.Greet($"{request.Name} {++i}");
            await responseStream.WriteAsync(new HelloReply { Message = message });

            await Task.Delay(1000);
        }
    }

    public override async Task<HelloReply> SayHelloClientStreaming(
        IAsyncStreamReader<HelloRequest> requestStream, ServerCallContext context)
    {
        var names = new List<string>();

        await foreach (var request in requestStream.ReadAllAsync())
        {
            names.Add(request.Name);
        }

        var message = _greeter.Greet(string.Join(", ", names));
        return new HelloReply { Message = message };
    }

    public override async Task SayHelloBidirectionalStreaming(
        IAsyncStreamReader<HelloRequest> requestStream,
        IServerStreamWriter<HelloReply> responseStream,
        ServerCallContext context)
    {
        await foreach (var request in requestStream.ReadAllAsync())
        {
            await responseStream.WriteAsync(
                new HelloReply { Message = _greeter.Greet(request.Name) });
        }
    }
}

Servizio gRPC precedente:

Servizi gRPC di unit test

Una libreria di unit test può testare direttamente i servizi gRPC chiamando i relativi metodi. Gli unit test testano un servizio gRPC in isolamento.

[Fact]
public async Task SayHelloUnaryTest()
{
    // Arrange
    var mockGreeter = new Mock<IGreeter>();
    mockGreeter.Setup(
        m => m.Greet(It.IsAny<string>())).Returns((string s) => $"Hello {s}");
    var service = new TesterService(mockGreeter.Object);

    // Act
    var response = await service.SayHelloUnary(
        new HelloRequest { Name = "Joe" }, TestServerCallContext.Create());

    // Assert
    mockGreeter.Verify(v => v.Greet("Joe"));
    Assert.Equal("Hello Joe", response.Message);
}

Lo unit test precedente:

  • Simula l'uso di IGreeter Moq.
  • Esegue il SayHelloUnary metodo con un messaggio di richiesta e un oggetto ServerCallContext. Tutti i metodi del servizio hanno un ServerCallContext argomento . In questo test il tipo viene fornito usando il TestServerCallContext.Create() metodo helper. Questo metodo helper è incluso nel codice di esempio.
  • Crea asserzioni:
    • Verifica che il nome della richiesta venga passato a IGreeter.
    • Il servizio restituisce il messaggio di risposta previsto.

Unit test HttpContext nei metodi gRPC

I metodi gRPC possono accedere a una richiesta HttpContext usando il ServerCallContext.GetHttpContext metodo di estensione. Per eseguire unit test di un metodo che usa HttpContext, il contesto deve essere configurato nell'installazione di test. Se HttpContext non è configurato, GetHttpContext restituisce null.

Per configurare un oggetto HttpContext durante l'installazione dei test, creare una nuova istanza e aggiungerla alla ServerCallContext.UserState raccolta usando la __HttpContext chiave .

var httpContext = new DefaultHttpContext();

var serverCallContext = TestServerCallContext.Create();
serverCallContext.UserState["__HttpContext"] = httpContext;

Eseguire i metodi del servizio con questo contesto di chiamata per usare l'istanza configurata HttpContext .

Servizi GRPC di test di integrazione

I test di integrazione valutano i componenti di un'app in un livello più ampio rispetto agli unit test. L'app gRPC è ospitata in TestServer, un server di test in memoria dal Microsoft.AspNetCore.TestHost pacchetto.

Una libreria di unit test avvia l'app gRPC e quindi i servizi gRPC vengono testati usando il client gRPC.

Il codice di esempio contiene l'infrastruttura per rendere possibile il test di integrazione:

  • La GrpcTestFixture<TStartup> classe configura l'host ASP.NET Core e avvia l'app gRPC in un server di test in memoria.
  • La IntegrationTestBase classe è il tipo di base da cui ereditano i test di integrazione. Contiene lo stato e le API della fixture per la creazione di un client gRPC per chiamare l'app gRPC.
[Fact]
public async Task SayHelloUnaryTest()
{
    // Arrange
    var client = new Tester.TesterClient(Channel);

    // Act
    var response = await client.SayHelloUnaryAsync(new HelloRequest { Name = "Joe" });

    // Assert
    Assert.Equal("Hello Joe", response.Message);
}

Test di integrazione precedente:

  • Crea un client gRPC usando il canale fornito da IntegrationTestBase. Questo tipo è incluso nel codice di esempio.
  • Chiama il SayHelloUnary metodo usando il client gRPC.
  • Asserisce che il servizio restituisce il messaggio di risposta previsto.

Inserire dipendenze fittizie

Usare ConfigureWebHost nella fixture per eseguire l'override delle dipendenze. L'override delle dipendenze è utile quando una dipendenza esterna non è disponibile nell'ambiente di test. Ad esempio, un'app che usa un gateway di pagamento esterno non deve chiamare la dipendenza esterna durante l'esecuzione dei test. Usare invece un gateway fittizio per il test.

public MockedGreeterServiceTests(GrpcTestFixture<Startup> fixture,
    ITestOutputHelper outputHelper) : base(fixture, outputHelper)
{
    var mockGreeter = new Mock<IGreeter>();
    mockGreeter.Setup(
        m => m.Greet(It.IsAny<string>())).Returns((string s) =>
        {
            if (string.IsNullOrEmpty(s))
            {
                throw new ArgumentException("Name not provided.");
            }
            return $"Test {s}";
        });

    Fixture.ConfigureWebHost(builder =>
    {
        builder.ConfigureServices(
            services => services.AddSingleton(mockGreeter.Object));
    });
}

[Fact]
public async Task SayHelloUnaryTest_MockGreeter_Success()
{
    // Arrange
    var client = new Tester.TesterClient(Channel);

    // Act
    var response = await client.SayHelloUnaryAsync(
        new HelloRequest { Name = "Joe" });

    // Assert
    Assert.Equal("Test Joe", response.Message);
}

Test di integrazione precedente:

  • Nel costruttore della classe di test (MockedGreeterServiceTests):
    • Simula l'uso di IGreeter Moq.
    • Esegue l'override dell'oggetto registrato con l'inserimento IGreeter delle dipendenze tramite ConfigureWebHost.
  • Chiama il SayHelloUnary metodo usando il client gRPC.
  • Asserisce il messaggio di risposta previsto in base all'istanza fittizia IGreeter .

Risorse aggiuntive