Nat*_*lor 4 c# unit-testing httpresponse asp.net-core
我有一个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);
}
}
Run Code Online (Sandbox Code Playgroud)
这可以按预期工作,但是我不确定为这种实际触发的中间件编写单元测试的最佳方法HttpResponse.OnStarting()。我唯一能想到的就是使用a Microsoft.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();
});
}
}
Run Code Online (Sandbox Code Playgroud)
有没有一种方法可以HttpResponse.OnStarting()在没有端到端集成测试的情况下触发传递给我的中间件的HttpContext?
在仓库中进行一些挖掘并查看了他们的一些测试之后,我想到了这个想法,以利用受控上下文的响应功能。
这意味着需要找到一种方法来捕获传递给的回调OnStarting。决定尝试通过虚拟响应功能来获取它。
private class DummyResponseFeature : IHttpResponseFeature {
public Stream Body { get; set; }
public bool HasStarted { get { return hasStarted; } }
public IHeaderDictionary Headers { get; set; }
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);
}
}
Run Code Online (Sandbox Code Playgroud)
在测试中,我将在上设置功能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()
}
Run Code Online (Sandbox Code Playgroud)
在中间件中等待请求委托时,让请求委托调用来捕获该回调
| 归档时间: |
|
| 查看次数: |
1623 次 |
| 最近记录: |