【问题标题】:How to unit test a .NET middleware that uses Response.OnStarting如何对使用 Response.OnStarting 的 .NET 中间件进行单元测试
【发布时间】:2020-01-03 18:15:28
【问题描述】:

因此,我创建了一个 .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);
}

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

【问题讨论】:

  • @Dai 嗯,不。我希望能够在不涉及控制器(或整个管道)的情况下对这个中间件进行单元测试。
  • 我链接到那个 QA 是因为它展示了如何构造一个用于测试的 HttpContext 实例——而不是因为它实例化了一个控制器。

标签: c# asp.net-core testing middleware xunit


【解决方案1】:

您可以使用Mock HttpContext for unit testing a .NET core MVC controller? 中的示例作为指导:

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

}

【讨论】:

  • 哦,我尝试过类似的方法,但没有“Headers.TryGetValue”和“Response.StartAsync”。我收到的错误正是响应尚未开始。
  • 我要在这里测试。谢谢!!
  • @Dai 我已经尝试过了,但await ctx.Response.StartAsync( default ); 实际上并没有为我启动响应。我仍然将 HasStarted 设为 false 并且它没有转到 OnStarting 函数。有什么见解吗?
  • @KemalTezerDilsiz 你在使用 xUnit 吗?其他async 方法是否按预期工作?您使用的是哪个版本的 .NET Core 和 ASP.NET Core?
  • @Dai 我正在使用 Moq 和最新的 ASP.NET Core,像这样(有点简化):gist.github.com/kedilsiz/d04f6d00a0414c11cb6957ed4edddf85
【解决方案2】:

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

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

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

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

【讨论】:

  • 您是如何让 Configure 部分工作的?对我来说,MS 提供的完全相同的代码并没有构建,它完全缺乏这种方法。这可能是一个命名空间问题,虽然我不知道哪个是罪魁祸首,因为我只使用Microsoft.Extensions.HostingMicrosoft.AspNetCore.TestHostXUnit,当然除了System.Threading.Tasks
  • @rTECH 也许Microsoft.AspNetCore.Hosting?
  • 这是HostBuilder 的命名空间,除非TestHost 内部有另一个实现我的VS 2019 由于某种原因找不到。
  • 基本上,你是对的。 Hostbuilder 在Extensions.Hosting,但我还需要添加AspNetCore.Hosting 虽然AspNetCore.Hosting 中没有Hostbuilder,只有一个WebhostBuilder,但这似乎不一样。
猜你喜欢
  • 2015-11-01
  • 1970-01-01
  • 2018-05-08
  • 1970-01-01
  • 2012-01-08
  • 1970-01-01
  • 2018-01-06
  • 1970-01-01
  • 2017-04-13
相关资源
最近更新 更多