为了账号安全,请及时绑定邮箱和手机立即绑定

单元测试ASP.NET Core HttpResponse.OnStarting()

单元测试ASP.NET Core HttpResponse.OnStarting()

C#
手掌心 2021-03-30 09:39:00
我有一个ASP.NET Core中间件,负责将标头添加到响应中。按照以下最佳实践,我将在的上下文中执行标头更改HttpResponse.OnStarting(Func<Task>),以确保在将响应刷新到客户端之前立即执行回调。public class ResponseHeadersMiddleware{    private readonly RequestDelegate _next;    public ResponseHeadersMiddleware(RequestDelegate next)    {        _next = next;    }    public async Task Invoke(HttpContext context)    {        context.Response.OnStarting(() =>        {            context.Response.Headers.Add("X-Some-Header", "Foobar");            return Task.CompletedTask;        });        // Pass the request through the pipeline         await _next(context);    }}这可以按预期工作,但是我不确定为这种实际触发的中间件编写单元测试的最佳方式HttpResponse.OnStarting()。我唯一能想到的就是使用aMicrosoft.AspNetCore.TestHost构建TestServer集成中间件并执行完整请求管道的a。尽管功能正常,但它更像是一个集成测试,而不是真正的单元测试。[Fact]public async Task when_adding_response_headers(){    // ARRANGE    var subject = new TestServer(new WebHostBuilder()        .UseStartup<TestStartup<ResponseHeadersMiddleware>>());    // ACT    var response = await subject.CreateClient()        .SendAsync(new HttpRequestMessage(HttpMethod.Get, "/")); // middleware fires for all requests    // ASSERT    Assert.True(response.Headers.TryGetValues("X-Some-Header", out var someHeader));    Assert.Equals("Foobar", someHeader.FirstOrDefault()}private class TestStartup<TMiddleware> where TMiddleware : class{    public void ConfigureServices(IServiceCollection services)    {        RequestDelegate requestDelegate = context => Task.FromResult(0);        services.AddSingleton(requestDelegate);        services.AddSingleton<TMiddleware>();    }    public void Configure(IApplicationBuilder app)    {        dynamic middleware = app.ApplicationServices.GetService(typeof(TMiddleware));        app.Use(async (ctx, next) =>        {            await middleware.Invoke(ctx);            await next();        });    }}有没有一种方法可以HttpResponse.OnStarting()在没有进行端到端集成测试的情况下触发传递给我的中间件的HttpContext?
查看完整描述

2 回答

?
慕盖茨4494581

TA贡献1850条经验 获得超11个赞

在仓库中进行一些挖掘并查看了他们的一些测试之后,我想到了这个想法,以利用受控上下文的响应功能。


这意味着需要找到一种方法来捕获传递给的回调OnStarting。决定尝试通过虚拟响应功能来获取它。


private class DummyResponseFeature : IHttpResponseFeature {

    public Stream Body { get; set; }


    public bool HasStarted { get { return hasStarted; } }


    public IHeaderDictionary Headers { get; set; } = new HeaderDictionary();


    public string ReasonPhrase { get; set; }


    public int StatusCode { get; set; }


    public void OnCompleted(Func<object, Task> callback, object state) {

        //...No-op

    }


    public void OnStarting(Func<object, Task> callback, object state) {

        this.callback = callback;

        this.state = state;

    }

    

    bool hasStarted = false;

    Func<object, Task> callback;

    object state;

    

    public Task InvokeCallBack() {

        hasStarted = true;

        return callback(state);

    }

}

在测试中,我将在上设置功能HttpContext,然后直接测试中间件。


[Fact]

public async Task when_adding_response_headers() {

    // ARRANGE

    var feature = new DummyResponseFeature();

    var context = new DefaultHttpContext();

    context.Features.Set<IHttpResponseFeature>(feature);

    

    RequestDelegate next = async (ctx) => {

        await feature.InvokeCallBack();

    };

    

    var subject = new ResponseHeadersMiddleware(next);


    // ACT

    await subject.Invoke(context);


    // ASSERT

    var response = context.Response;

    Assert.True(response.Headers.TryGetValues("X-Some-Header", out var someHeader));

    Assert.Equals("Foobar", someHeader.FirstOrDefault()

}

在中间件中等待请求委托时,让请求委托调用来捕获该回调


查看完整回答
反对 回复 2021-04-10
  • 2 回答
  • 0 关注
  • 330 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信