.NET Core单元测试:ForwardedHeaders配置及中间件上下文验证
.NET Core扩展方法单元测试实现方案
一、验证AddProxyForwardedHeaders配置是否正确
这个扩展方法的核心是配置ForwardedHeadersOptions,无需启动TestServer,直接从服务容器中解析配置项断言即可,高效且直接。
测试思路
- 创建空的
ServiceCollection实例 - 调用
AddProxyForwardedHeaders扩展方法 - 构建服务提供者,获取配置好的
ForwardedHeadersOptions - 逐一验证各项配置是否符合预期
测试代码示例(xUnit)
using Microsoft.Extensions.DependencyInjection; using Microsoft.AspNetCore.HttpOverrides; using Xunit; public class ProxyForwardedHeadersExtensionsTests { [Fact] public void AddProxyForwardedHeaders_ConfiguresOptionsCorrectly() { // Arrange var services = new ServiceCollection(); // Act services.AddProxyForwardedHeaders(); var serviceProvider = services.BuildServiceProvider(); var options = serviceProvider.GetRequiredService<IOptions<ForwardedHeadersOptions>>().Value; // Assert Assert.Null(options.ForwardLimit); Assert.False(options.RequireHeaderSymmetry); Assert.Empty(options.KnownNetworks); Assert.Empty(options.KnownProxies); Assert.Equal( ForwardedHeaders.XForwardedHost | ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto, options.ForwardedHeaders); } }
二、验证UseProxyForwardedHeaders中间件的上下文修改逻辑
针对中间件的测试,提供两种可行方案:通过TestServer模拟请求,或直接构造HttpContext测试中间件逻辑。
方案1:使用TestServer模拟请求
通过自定义端点捕获请求上下文状态,验证中间件的修改效果。
测试代码示例
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.Hosting; using Xunit; using System.Net.Http; using System.Threading.Tasks; public class ProxyForwardedHeadersMiddlewareTests { [Theory] [InlineData("/my-service", "/my-service", "https")] [InlineData("", "/", "http")] // 空服务名时保持原Scheme和PathBase public async Task UseProxyForwardedHeaders_ModifiesContextCorrectly(string serviceName, string expectedPathBase, string expectedScheme) { // Arrange var hostBuilder = new HostBuilder() .ConfigureWebHost(webBuilder => { webBuilder .UseTestServer() .ConfigureServices(services => services.AddRouting()) .Configure(app => { app.UseProxyForwardedHeaders(serviceName); // 自定义端点返回当前请求的Scheme和PathBase app.UseEndpoints(endpoints => { endpoints.MapGet("/", context => { var result = $"Scheme:{context.Request.Scheme};PathBase:{context.Request.PathBase}"; return context.Response.WriteAsync(result); }); }); }); }); var host = await hostBuilder.StartAsync(); var client = host.GetTestClient(); // Act var response = await client.GetAsync("/"); response.EnsureSuccessStatusCode(); var content = await response.Content.ReadAsStringAsync(); // Assert Assert.Contains($"Scheme:{expectedScheme}", content); Assert.Contains($"PathBase:{expectedPathBase}", content); } }
方案2:直接测试中间件委托
无需启动服务器,手动构造HttpContext和中间件委托,验证逻辑正确性。
测试代码示例
using Microsoft.AspNetCore.Http; using Xunit; using System.Threading.Tasks; public class ProxyForwardedHeadersMiddlewareDirectTests { [Fact] public async Task UseProxyForwardedHeaders_WithValidServiceName_ModifiesSchemeAndPathBase() { // Arrange var context = new DefaultHttpContext(); context.Request.Scheme = "http"; context.Request.PathBase = new PathString(""); string serviceName = "/test-service"; bool nextCalled = false; Task next() { nextCalled = true; return Task.CompletedTask; } // 提取中间件核心逻辑 var testMiddleware = new Func<HttpContext, Func<Task>, Task>((ctx, nextFunc) => { if (string.IsNullOrWhiteSpace(serviceName)) { return nextFunc(); } ctx.Request.Scheme = "https"; ctx.Request.PathBase = new PathString(serviceName); return nextFunc(); }); // Act await testMiddleware(context, next); // Assert Assert.True(nextCalled); Assert.Equal("https", context.Request.Scheme); Assert.Equal(serviceName, context.Request.PathBase.Value); } [Fact] public async Task UseProxyForwardedHeaders_WithEmptyServiceName_DoesNotModifyContext() { // Arrange var context = new DefaultHttpContext(); context.Request.Scheme = "http"; context.Request.PathBase = new PathString("/original"); string serviceName = ""; bool nextCalled = false; Task next() { nextCalled = true; return Task.CompletedTask; } var testMiddleware = new Func<HttpContext, Func<Task>, Task>((ctx, nextFunc) => { if (string.IsNullOrWhiteSpace(serviceName)) { return nextFunc(); } ctx.Request.Scheme = "https"; ctx.Request.PathBase = new PathString(serviceName); return nextFunc(); }); // Act await testMiddleware(context, next); // Assert Assert.True(nextCalled); Assert.Equal("http", context.Request.Scheme); Assert.Equal("/original", context.Request.PathBase.Value); } }
内容的提问来源于stack exchange,提问作者user20532587
相关产品推荐
相关产品推荐

