如何在Asp.Net Core中测试中间件

在上一章节中,我们实践了在Asp.Net Core项目中的实际操作。本章将介绍如何测试Asp.Net Core中的中间件。

TestServer

你还记得我们在集成测试中提到的TestServer吗?TestServer是由Microsoft.AspNetCore.TestHost包提供的,它包含了用于在测试环境中模拟ASP.NET Core应用程序的类和方法。通过使用TestServer,开发人员可以在测试中模拟整个应用程序的运行环境,包括中间件的执行,从而进行集成测试和端到端测试。

中间件可以使用TestServer单独测试。这样可以实例化只包含需要测试的组件的应用管道,并发送自定义请求以验证中间件行为。

  • 请求会发送到内存中,而不是通过网络进行序列化。
  • 可以避免产生额外的问题,例如端口管理和HTTPS证书。
  • 中间件中的异常可以直接流回调用测试。
  • 可以直接在测试中自定义服务器数据结构,如HttpContext。

实战

首先,在VS中新建测试项目dotNetParadise.MiddlerWareTest,并进行Nuget安装Microsoft.AspNetCore.TestHost。

PM> NuGet\Install-Package Microsoft.AspNetCore.TestHost -Version 8.0.4

接下来,我们需要在Sample.Api中创建一个中间件。

定义MyMiddleware中间件

public class MyMiddleware(RequestDelegate next)
{
    public async Task InvokeAsync(HttpContext context)
    {
        // 在请求处理前执行的逻辑
        context.Response.ContentType = "text/plain";
        context.Response.Headers.TryAdd("X-Custom-Header", "CustomValue");
        await context.Response.WriteAsync("Test My Middleware");
        // 调用下一个中间件
        await next(context);
        // 在请求处理后执行的逻辑
        await context.Response.WriteAsync("Middleware Test Completed");
    }
}

定义测试类

// Arrange
using var host = await new HostBuilder()
    .ConfigureWebHost(webBuilder =>
    {
        webBuilder
            .UseTestServer()
            .ConfigureServices(services =>
            {
                // 在这里可以注入服务
            })
            .Configure(app =>
            {
                app.UseMiddleware<MyMiddleware>();
            });
    })
    .StartAsync();

// Act
var response = await host.GetTestClient().GetAsync("/");

// Assert
response.EnsureSuccessStatusCode(); // 确保请求成功
var responseContent = await response.Content.ReadAsStringAsync();
Assert.Contains("Test My Middleware", responseContent);
Assert.Contains("Middleware Test Completed", responseContent);


Run Test

使用HttpContext发送请求

可以使用TestServer来设置测试环境,并创建一个模拟的HttpContext对象来代表一个请求。

[Fact]
public async Task TestMiddleware_ExpectedResponse()
{
    using var host = await new HostBuilder()
        .ConfigureWebHost(webBuilder =>
        {
            webBuilder
                .UseTestServer()
                .ConfigureServices(services =>
                {
                })
                .Configure(app =>
                {
                    app.UseMiddleware<MyMiddleware>();
                });
        })
        .StartAsync();

    var server = host.GetTestServer();
    server.BaseAddress = new Uri("http://localhost");

    var context = await server.SendAsync(c =>
    {
        c.Request.Method = HttpMethods.Get;
        c.Request.Path = "/";
        c.Request.Host = new HostString("localhost");
        c.Request.Scheme = "http";
    });
    //act
    Assert.True(context.RequestAborted.CanBeCanceled);
    Assert.Equal(HttpProtocol.Http11, context.Request.Protocol);
    // 验证响应
    Assert.Equal(StatusCodes.Status200OK, context.Response.StatusCode);
    var customHeader = context.Response.Headers["X-Custom-Header"].ToString();
    Assert.Equal("CustomValue", customHeader);
}


使用SendAsync的好处包括:


通过设置HttpContext的任何属性,从而精确控制请求的各个方面。相比于使用HttpClient,SendAsync通常更快,因为它绕过了网络层。集成测试:这是测试整个请求处理管道(包括所有中间件)的好方法。然而,它也有一些限制。


局限性:


SendAsync主要用于集成测试,而不是单元测试。它测试的是整个请求处理流程,而不是单个组件。模拟限制:虽然你可以设置HttpContext的许多属性来模拟请求,但某些方面(如用户认证状态或外部依赖项)可能难以完全模拟。

添加请求路由

在TestServer中添加路由的功能和Asp.Net Core中添加路由基本一致。

[Fact]
public async Task TestWithEndpoint_ExpectedResponse()
{
    using var host = await new HostBuilder()
        .ConfigureWebHost(webBuilder =>
        {
            webBuilder
                .UseTestServer()
                .ConfigureServices(services =>
                {
                    services.AddRouting();
                })
                .Configure(app =>
                {
                    app.UseRouting();
                    app.UseEndpoints(endpoints =>
                    {
                        endpoints.MapGet("/hello", () =>
                            TypedResults.Text("Hello Tests"));
                    });
                });
        })
        .StartAsync();

    var client = host.GetTestClient();

    var response = await client.GetAsync("/hello");

    Assert.True(response.IsSuccessStatusCode);
    var responseBody = await response.Content.ReadAsStringAsync();
    Assert.Equal("Hello Tests", responseBody);
}

在测试场景中,添加请求路由的好处主要体现在以下几个方面:

  • 模拟真实环境:通过添加请求路由,你可以模拟出与真实生产环境相似的请求处理流程。这使得测试更加接近实际使用情况,从而提高了测试的可靠性和有效性。
  • 控制测试的粒度:你可以针对特定的路由进行精确测试,确保每个路由都能正确响应并返回预期的结果。这有助于发现潜在的路由错误或逻辑问题,提高了测试的精度。
  • 隔离测试:在测试过程中,你可以通过配置路由来隔离特定的功能或组件,从而避免其他部分的干扰。这种隔离测试有助于更准确地定位问题,提高了测试的效率。
  • 模拟异常场景:通过配置路由,你可以模拟各种异常场景,如路由不存在、参数错误等。这有助于测试应用程序在异常情况下的响应和处理能力,提高了应用程序的健壮性。
  • 自动化测试:在自动化测试框架中,添加请求路由可以使得测试用例更加易于编写和执行。通过发送请求到特定的路由并验证响应,你可以自动化地检查应用程序的功能和性能。

最后

本章我们探讨了如何在Asp.Net Core项目中测试中间件的方法和技巧。通过使用TestServer和HttpContext发送请求,我们可以模拟整个应用程序的运行环境,从而进行集成测试和端到端测试。同时,我们也介绍了如何添加请求路由来模拟不同的场景,并对中间件的行为进行验证。

通过测试中间件,我们可以确保其在处理请求时的行为符合预期,提高应用程序的稳定性和可靠性。测试不仅可以帮助发现潜在的问题,还可以在开发过程中及早发现和解决bug,提高代码质量和开发效率。


?欢迎关注笔者公众号一起学习交流,获取更多有用的知识~

  • 测试中间件
  • 本文完整源代码

未经允许不得转载:大白鲨游戏网 » 如何在Asp.Net Core中测试中间件