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

为何C#单元测试中抛出模拟异常时全局异常处理未触发?

问题原因

全局异常处理器是ASP.NET Core请求管道的专属组件,只有当请求走完整管道(比如真实HTTP请求、集成测试的TestServer模拟请求)时,才会触发它的异常捕获逻辑。你现在的单元测试是直接调用控制器的方法,相当于跳过了整个请求管道,所以依赖抛出的异常会直接从控制器方法中冒泡出来,根本不会被全局处理器捕获。

解决方案

分两种场景处理:

场景1:仅测试控制器核心逻辑(不验证全局异常处理)

如果你的目标是确认控制器在依赖出错时会正确抛出异常(把异常交给上层管道处理),直接调整测试来捕获异常即可:

[Fact]
public async Task GetCustomerById_ThrowsExceptionWhenDbFails()
{
    // Arrange
    var customerId = 1;
    _customerRepoMock
        .Setup(repo => repo.GetOne(customerId))
        .ThrowsAsync(new Exception("Wrong or missing DB conn string"));

    // Act & Assert
    await Assert.ThrowsAsync<Exception>(() => _controller.RetrieveCustomerById(customerId));
}

场景2:验证全局异常处理器的输出效果

如果要验证全局处理器返回的500错误和自定义响应内容,单元测试做不到,必须用集成测试,通过TestServer模拟完整的请求管道:

public class CustomerControllerIntegrationTests : IClassFixture<WebApplicationFactory<Program>>
{
    private readonly HttpClient _client;
    private readonly WebApplicationFactory<Program> _factory;

    public CustomerControllerIntegrationTests(WebApplicationFactory<Program> factory)
    {
        _factory = factory;
        // 替换依赖,模拟数据库异常
        _client = _factory.WithWebHostBuilder(builder =>
        {
            builder.ConfigureServices(services =>
            {
                var repoDescriptor = services.SingleOrDefault(d => d.ServiceType == typeof(ICustomerRepo));
                if (repoDescriptor != null)
                {
                    services.Remove(repoDescriptor);
                    var mockRepo = new Mock<ICustomerRepo>();
                    mockRepo.Setup(repo => repo.GetOne(1))
                        .ThrowsAsync(new Exception("Wrong or missing DB conn string"));
                    services.AddSingleton(mockRepo.Object);
                }
            });
        }).CreateClient();
    }

    [Fact]
    public async Task GetCustomerById_Returns500WhenDbFails()
    {
        // Act
        var response = await _client.GetAsync("/api/customers/1");

        // Assert
        Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode);
        // 可选:验证自定义错误响应体
        var errorContent = await response.Content.ReadFromJsonAsync<MyCustomErrorModel>();
        Assert.NotNull(errorContent);
        Assert.Contains("Wrong or missing DB conn string", errorContent.Message);
    }
}
总结
  • 单元测试直接调用控制器方法时,不会触发全局异常处理器,因为跳过了ASP.NET Core请求管道。
  • 仅验证控制器逻辑:捕获抛出的异常即可。
  • 验证全局异常处理的实际效果:必须用集成测试模拟完整请求流程。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 13:02:43