Partager via


Tester les services gRPC dans ASP.NET Core

Remarque

Ceci n’est pas la dernière version de cet article. Pour la version actuelle, consultez la version .NET 9 de cet article.

Avertissement

Cette version d’ASP.NET Core n’est plus prise en charge. Pour plus d’informations, consultez la stratégie de support .NET et .NET Core. Pour la version actuelle, consultez la version .NET 9 de cet article.

Important

Ces informations portent sur la préversion du produit, qui est susceptible d’être en grande partie modifié avant sa commercialisation. Microsoft n’offre aucune garantie, expresse ou implicite, concernant les informations fournies ici.

Pour la version actuelle, consultez la version .NET 9 de cet article.

Par : James Newton-King

Les tests sont un aspect important de la création de logiciels stables et maintenables. Cet article explique comment tester les services gRPC ASP.NET Core.

Il existe trois approches courantes pour tester les services gRPC :

  • Test unitaire : testez les services gRPC directement à partir d’une bibliothèque de tests unitaires.
  • Test d’intégration : l’application gRPC est hébergée dans TestServer, un serveur de test en mémoire à partir du package Microsoft.AspNetCore.TestHost. Les services gRPC sont testés en les appelant à l’aide d’un client gRPC à partir d’une bibliothèque de test unitaire.
  • Test manuel : testez les serveurs gRPC avec des appels ad hoc. Pour plus d’informations sur l’utilisation des outils de ligne de commande et d’interface utilisateur avec les services gRPC, consultez Tester les services gRPCurl avec gRPCui dans ASP.NET Core.

Dans les tests unitaires, seul le service gRPC est impliqué. Les dépendances injectées dans le service doivent être moquées. Dans les tests d’intégration, le service gRPC et son infrastructure auxiliaire font partie du test. Cela inclut le démarrage de l’application, l’injection de dépendances, le routage et l’authentification et l’autorisation.

Exemple de service testable

Pour illustrer les tests de service, passez en revue le service suivant dans l’échantillon d’application.

Affichez ou téléchargez l’exemple de code (procédure de téléchargement)

Le TesterService retourne les salutations avec les quatre types de méthode de 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) });
        }
    }
}

Le service gRPC précédent :

Services gRPC de test unitaire

Une bibliothèque de tests unitaires peut tester directement les services gRPC en appelant ses méthodes. Les tests unitaires testent un service gRPC isolé.

[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);
}

Le test unitaire précédent :

  • IGreeter fictif à l’aide de Moq.
  • Exécute la méthode SayHelloUnary avec un message de requête et un ServerCallContext. Toutes les méthodes de service ont un argument ServerCallContext. Dans ce test, le type est fourni à l’aide de la méthode d’assistance TestServerCallContext.Create(). Cette méthode d’assistance est incluse dans l’échantillon de code.
  • Effectue des assertions :
    • Vérifie que le nom de la requête est passé à IGreeter.
    • Le service retourne le message de réponse attendu.

Test unitaire HttpContext dans les méthodes gRPC

Les méthodes gRPC peuvent accéder aux requêtes HttpContext à l’aide de la méthode d’extension ServerCallContext.GetHttpContext. Pour tester unitairement une méthode qui utilise HttpContext, le contexte doit être configuré dans le programme d’installation de test. Si HttpContext n’est pas configuré, GetHttpContext retourne null.

Pour configurer un HttpContext pendant la configuration du test, créez un instance et ajoutez-la à la collection ServerCallContext.UserState à l’aide de la clé __HttpContext.

var httpContext = new DefaultHttpContext();

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

Exécutez des méthodes de service avec ce contexte d’appel pour utiliser l’instance HttpContext configurée.

Services gRPC de test d’intégration

Les tests d’intégration évaluent les composants d’une application à un niveau plus large que les tests unitaires. L’application gRPC est hébergée dans TestServer, un serveur de test en mémoire à partir du package Microsoft.AspNetCore.TestHost.

Une bibliothèque de tests unitaires démarre l’application gRPC, puis les services gRPC sont testés à l’aide du client gRPC.

L’échantillon de code contient l’infrastructure pour rendre possible le test d’intégration :

  • La classe GrpcTestFixture<TStartup> configure l’hôte ASP.NET Core et démarre l’application gRPC dans un serveur de test en mémoire.
  • La classe IntegrationTestBase est le type de base dont héritent les tests d’intégration. Il contient l’état de la fixation et les API permettant de créer un client gRPC pour appeler l’application 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);
}

Le test d’intégration précédent :

  • Crée un client gRPC à l’aide du canal fourni par IntegrationTestBase. Ce type est inclus dans l’échantillon de code.
  • Appelle la méthode SayHelloUnary à l’aide du client gRPC.
  • Affirme que le service retourne le message de réponse attendu.

Injecter des dépendances fictives

Utilisez ConfigureWebHost sur la fixture pour remplacer les dépendances. Le remplacement de dépendances est utile lorsqu’une dépendance externe n’est pas disponible dans l’environnement de test. Par exemple, une application qui utilise une passerelle de paiement externe ne doit pas appeler la dépendance externe lors de l’exécution de tests. Utilisez plutôt une passerelle factice pour le 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);
}

Le test d’intégration précédent :

  • Dans le constructeur de la classe de test (MockedGreeterServiceTests) :
    • IGreeter fictif à l’aide de Moq.
    • Remplace le IGreeter inscrit avec l’injection de dépendances à l’aide de ConfigureWebHost.
  • Appelle la méthode SayHelloUnary à l’aide du client gRPC.
  • Assertion du message de réponse attendu en fonction de l’instance fictive IGreeter.

Ressources supplémentaires