【发布时间】:2018-04-09 19:21:57
【问题描述】:
我有一个 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() 的中间件编写单元测试。我唯一能想到的是使用Microsoft.AspNetCore.TestHost 构建一个TestServer,它集成了中间件并执行完整的请求管道。虽然功能齐全,但这更像是一个集成测试,而不是真正的单元测试。
[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();
});
}
}
有没有办法在传递给我的中间件的 HttpContext 上触发 HttpResponse.OnStarting(),而无需端到端集成测试?
【问题讨论】:
-
这是一个有趣的问题。您是否考虑过模拟一个响应对象并将其与测试中使用的 HttpContext 一起使用。
-
是的。在模拟/假 HttpContext 上调用 Invoke!从你那里的集成测试来看,它的优雅程度要低得多,而且它都是在内存中完成的,所以无论如何都会超级放大。好问题。有很多东西我想用 aspnetcore 进行测试,但如果没有类似地设置 testhost 就不行!
-
@Mardoxx 在查看了
DefaultHttpContext、DefaultHttpResponse和HttpResponseFeature的来源之后,我还没有确定传递给HttpResponse.OnStarting()的回调是如何被调用的。 github.com/aspnet/HttpAbstractions/blob/dev/src/…github.com/aspnet/HttpAbstractions/blob/dev/src/…github.com/aspnet/HttpAbstractions/blob/dev/src/… -
您需要测试该响应是否包含预期的标头 - 所以像测试整个管道一样测试它。 在查看...的源代码之后 - 您真的希望您的测试依赖于实现细节吗?不管你如何对测试“集成”或“单元”进行分类——它们都是断言你的应用程序按预期工作的测试,并且应该只按执行时间分类——>“慢”和“快”
标签: c# unit-testing asp.net-core httpresponse