如何对使用 Response.OnStarting 的 .NET 中间件进行单元测试

ren*_*ato 3 c# testing middleware xunit asp.net-core

因此,我创建了一个 .net 核心中间件,用于向响应添加标头。我没有找到对这个中间件进行单元测试的方法,因为它使用OnStarting回调,我无法想象如何模拟或强制执行它。

这是中间件的示例:

public async Task InvokeAsync(HttpContext context, RequestDelegate next)
{
    context.Response.OnStarting(() =>
    {
        context.Response.Headers.Add("Name", "Value");

        return Task.CompletedTask;
    });

    await next(context);
}
Run Code Online (Sandbox Code Playgroud)

由于中间件接口需要 的具体实例HttpContext,例如,我无法想象使用 来模拟它的方法FakeItEasy

Dai*_*Dai 5

您可以使用Mock HttpContext 中的示例对 .NET 核心 MVC 控制器进行单元测试吗?作为指南:

using Shouldly;
using Xunit;

[Fact]
public async Task Middleware_should_add_header()
{
    // Arrange:

    HttpContext ctx = new DefaultHttpContext();

    RequestDelegate next = ( HttpContext hc ) => Task.CompletedTask;

    MyMiddleware mw = new MyMiddleware();

    // Act - Part 1: InvokeAsync set-up:

    await hw.InvokeAsync( ctx, next );

    // Assert - Part 1

    ctx.Response.Headers.TryGetValue( "Name", out String value0 ).ShouldBeFalse();
    value0.ShouldBeNull();

    // Act - Part 2

    await ctx.Response.StartAsync( default );

    // Asset - Part 2

    ctx.Response.Headers.TryGetValue( "Name", out String value1 ).ShouldBeTrue();
    value1.ShouldBe( "Value" );

}
Run Code Online (Sandbox Code Playgroud)

  • @Dai 我已经尝试过这个,但是 `await ctx.Response.StartAsync( default );` 实际上并没有为我启动响应。我仍然得到 HasStarted 作为 false 并且它不会进入 OnStarting 函数。有什么见解吗? (2认同)

Joa*_*iro 5

如果按照微软的建议去做呢?https://learn.microsoft.com/en-us/aspnet/core/test/middleware?view=aspnetcore-3.1

您可以仅使用中间件所需的服务(根据需要模拟或存根)创建主机,而无需控制器。然后将 TestServer 附加到它并使用它来请求您的 api。

也许在提出问题时该文档不可用,但现在似乎是实现所需目标的最佳方法。

注意:不确定这些是否仍被视为单元测试,这取决于每个开发人员的定义。