You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让C# TestServer主动抛出异常以测试ErrorHandlingMiddleware

如何在TestServer中触发异常以测试ErrorHandlingMiddleware?

要测试中间件的异常捕获逻辑,你可以通过以下两种方式主动触发异常:

方法1:添加会抛出异常的测试端点(集成测试)

在TestServer的配置中新增一个专门抛出异常的测试路由,请求该路由时,后续的next委托会执行异常代码,被中间件的catch块捕获。

修改你的GetHost方法,在Configure中添加测试端点:

private async Task<IHost> GetHost()
{
    return await new HostBuilder()
        .ConfigureWebHost(webBuilder =>
        {
            webBuilder
                .UseTestServer()
                .ConfigureServices(services =>
                {
                    services.Add(ServiceDescriptor.Scoped<IErrorHandlingService, ErrorHandlingService>());
                })
                .Configure(app =>
                {
                    app.UseMiddleware<ErrorHandlingMiddleware>();
                    // 添加抛出异常的测试端点
                    app.MapGet("/test-throw-exception", () =>
                    {
                        throw new InvalidOperationException("测试异常:来自端点的错误");
                    });
                });
        })
        .StartAsync();
}

编写测试方法验证异常处理逻辑:

[Fact]
public async Task ExceptionThrown_ShouldBeHandledByMiddleware()
{
    // Arrange
    using var host = await GetHost();
    var server = host.GetTestServer();
    server.BaseAddress = new Uri("https://example.com/");

    // Act
    var response = await server.CreateRequest("/test-throw-exception")
        .GetAsync();

    // Assert
    // 验证响应状态码
    response.StatusCode.Should().Be((int)HttpStatusCode.InternalServerError);
    
    // 验证错误响应内容
    var errorResponse = await response.Content.ReadFromJsonAsync<ErrorResponse>();
    errorResponse.ErrorContent.ErrorMessage.Should().Contain("测试异常:来自端点的错误");
    errorResponse.ErrorContent.HttpCode.Should().Be(HttpStatusCode.InternalServerError);
    
    // 验证ErrorHandlingService的错误记录
    var errHandler = host.Services.GetRequiredService<IErrorHandlingService>();
    errHandler.ErrorResponse.ErrorContent.TraceID.Should().NotBeEmpty();
}

方法2:直接模拟抛出异常的RequestDelegate(单元测试)

如果想更聚焦中间件本身的逻辑,无需完整TestServer,可以直接构造中间件实例,传入会抛出异常的RequestDelegate,同时模拟依赖的IErrorHandlingService和IHostEnvironment。

示例代码(使用Moq框架):

[Fact]
public async Task Invoke_WhenNextThrowsException_HandlesErrorCorrectly()
{
    // Arrange
    // 模拟ErrorHandlingService
    var mockErrHandler = new Mock<IErrorHandlingService>();
    mockErrHandler.Setup(h => h.ErrorResponse).Returns(new ErrorResponse
    {
        ErrorContent = new ErrorContent(),
        StatusCode = HttpStatusCode.InternalServerError
    });

    // 模拟HostEnvironment(非生产环境)
    var mockEnv = new Mock<IHostEnvironment>();
    mockEnv.Setup(e => e.IsProduction()).Returns(false);

    // 定义会抛出异常的next委托
    var testException = new InvalidOperationException("测试异常:来自next委托");
    RequestDelegate next = _ => throw testException;

    // 构造中间件
    var middleware = new ErrorHandlingMiddleware(next, mockErrHandler.Object);
    var context = new DefaultHttpContext();

    // Act
    await middleware.Invoke(context, mockEnv.Object);

    // Assert
    // 验证响应状态码
    context.Response.StatusCode.Should().Be((int)HttpStatusCode.InternalServerError);
    
    // 验证ErrorHandlingService是否正确记录了错误
    mockErrHandler.Verify(h => h.AddError(It.Is<MyError>(err =>
        err.ErrorMessage.Contains(testException.ToString()) &&
        err.HttpCode == HttpStatusCode.InternalServerError &&
        err.Title == "An unknown error occurred during execution"
    )), Times.Once);
}

两种方法的区别

  • 方法1是集成测试,模拟真实HTTP请求流程,能验证中间件在完整管道中的表现;
  • 方法2是单元测试,直接测试中间件核心逻辑,运行更快,更易隔离问题。

内容的提问来源于stack exchange,提问作者penny

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 11:13:20