共用方式為


在 ASP.NET Core 中測試 gRPC 服務

注意

這不是這篇文章的最新版本。 如需目前的版本,請參閱 本文的 .NET 9 版本。

警告

不再支援此版本的 ASP.NET Core。 如需詳細資訊,請參閱 .NET 和 .NET Core 支持原則。 如需目前的版本,請參閱 本文的 .NET 9 版本。

重要

這些發行前產品的相關資訊在產品正式發行前可能會有大幅修改。 Microsoft 對此處提供的資訊,不做任何明確或隱含的瑕疵擔保。

如需目前的版本,請參閱 本文的 .NET 9 版本。

作者:James Newton-King

測試是建置穩定且可維護軟體的重要層面。 本文討論如何測試 ASP.NET Core gRPC 服務。

測試 gRPC 服務的常見方法有三種:

  • 單元測試:直接從單元測試程式庫測試 gRPC 服務。
  • 整合測試:gRPC 應用程式裝載於 TestServer 套件,這是來自 Microsoft.AspNetCore.TestHost 套件的記憶體內部測試伺服器。 透過從單元測試程式庫使用 gRPC 用戶端呼叫 gRPC 服務來進行測試。
  • 手動測試:使用臨機操作呼叫測試 gRPC 伺服器。 如需如何使用命令列和 UI 工具搭配 gRPC 服務的詳細資訊,請參閱在 ASP.NET Core 中使用 gRPCurl 和 gRPCui 測試 gRPC 服務

在單元測試中,只涉及 gRPC 服務。 必須模擬插入服務中的相依性。 在整合測試中,gRPC 服務及其輔助基礎結構是測試的一部分。 這包括應用程式啟動、相依性插入、路由和驗證,以及授權。

可測試服務範例

若要示範服務測試,請在範例應用程式中檢閱下列服務。

檢視或下載範例程式碼 \(英文\) (如何下載)

TesterService 會使用 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) });
        }
    }
}

上述 gRPC 服務:

單元測試 gRPC 服務

單元測試程式庫可以藉由呼叫其方法,直接測試 gRPC 服務。 單元測試會單獨測試 gRPC 服務。

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

上述單元測試:

  • 使用 Moq 模擬 IGreeter
  • 使用要求訊息和 ServerCallContext 執行 SayHelloUnary 方法。 所有服務方法都有 ServerCallContext 引數。 在此測試中,會使用 TestServerCallContext.Create() 協助程式方法提供類型。 此協助程式方法包含在程式碼範例中。
  • 進行判斷提示:
    • 確認要求名稱已傳遞至 IGreeter
    • 服務會傳回預期的回覆訊息。

gRPC 方法中的單元測試 HttpContext

gRPC 方法可以使用 ServerCallContext.GetHttpContext 擴充方法存取要求的 HttpContext。 若要對使用 HttpContext 的方法進行單元測試,必須在測試設定中設定內容。 如果未 HttpContext 設定 ,則 GetHttpContext 會傳回 null

若要在測試設定期間設定 HttpContext,請建立新的執行個體,並使用 __HttpContext 索引鍵將其新增至 ServerCallContext.UserState 集合。

var httpContext = new DefaultHttpContext();

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

使用此呼叫內容執行服務方法,以使用已設定的 HttpContext 執行個體。

整合測試 gRPC 服務

整合測試評估應用程式元件的層級比單元測試更廣泛。 gRPC 應用程式裝載於 TestServer,這是來自 Microsoft.AspNetCore.TestHost 套件的記憶體內部測試伺服器。

單元測試程式庫會啟動 gRPC 應用程式,然後使用 gRPC 用戶端測試 gRPC 服務。

範例程式碼包含基礎結構,可讓您進行整合測試:

  • 類別 GrpcTestFixture<TStartup> 會設定 ASP.NET Core 主機,並在記憶體內部測試伺服器中啟動 gRPC 應用程式。
  • 類別 IntegrationTestBase 是整合測試所繼承的基底類型。 其中包含用來建立 gRPC 用戶端以呼叫 gRPC 應用程式的測試固件狀態和 API。
[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);
}

上述整合測試:

  • 使用 IntegrationTestBase 所提供的通道建立 gRPC 用戶端。 此類型包含在範例程式碼中。
  • 使用 gRPC 用戶端呼叫 SayHelloUnary 方法。
  • 判斷提示此服務會傳回預期的回覆訊息。

插入模擬相依性

在測試固件上使用 ConfigureWebHost 來覆寫相依性。 在測試環境中無法使用外部相依性時,覆寫相依性很實用。 例如,使用外部付款閘道的應用程式不應該在執行測試時呼叫外部相依性。 請改用模擬閘道進行測試。

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

上述整合測試:

  • 在測試類別的 (MockedGreeterServiceTests) 建構函式中:
    • 使用 Moq 模擬 IGreeter
    • 使用 ConfigureWebHost 覆寫以相依性插入註冊的 IGreeter
  • 使用 gRPC 用戶端呼叫 SayHelloUnary 方法。
  • 根據模擬 IGreeter 執行個體判斷提示預期的回覆訊息。

其他資源