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

单元测试GetAsync时,如何让HttpResponseMessage抛出异常被捕获?

解决方案

要让GetAsync抛出异常被catch块捕获,核心是模拟HttpClient底层发送请求时发生错误的场景,而非单纯返回错误状态码。你之前的两种做法都没命中要点:

  • 返回500状态码属于正常响应,GetAsync不会自动抛出异常(需手动调用EnsureSuccessStatusCode才会触发);
  • 在GetHttpResponseMessage里直接throw会在Mock初始化阶段就抛出异常,而非调用GetAsync时触发。

正确的做法是在MockHttpMessageHandler的SendAsync方法时,让它异步抛出异常,具体实现如下:

完整Mock代码示例

// 1. Mock HttpMessageHandler,让SendAsync抛出异常
var handler = new Mock<HttpMessageHandler>();
handler
    .Protected()
    .Setup<Task<HttpResponseMessage>>(
        "SendAsync",
        ItExpr.IsAny<HttpRequestMessage>(),
        ItExpr.IsAny<CancellationToken>()
    )
    // 模拟发送请求时抛出异常,比如HttpRequestException
    .ThrowsAsync(new HttpRequestException("模拟网络请求失败"))
    .Verifiable();

// 2. 创建HttpClient并关联Mock的Handler
var httpClient = new HttpClient(handler.Object)
{
    BaseAddress = new Uri("http://localhost:7100")
};

// 3. Mock IHttpClientFactory返回上述HttpClient
var factory = new Mock<IHttpClientFactory>();
factory.Setup(_ => _.CreateClient(It.IsAny<string>()))
       .Returns(httpClient)
       .Verifiable();

关键说明

  • 使用ThrowsAsync而非Throws:因为SendAsync是异步方法,必须用异步抛出方法才能在调用GetAsync时触发异常;
  • 建议抛出特定异常类型:比如HttpRequestException(HttpClient实际场景中最常抛出的异常类型),而非通用的Exception,更贴近真实业务场景;
  • 若要模拟取消请求异常,可以抛出OperationCanceledException,对应传入已取消的CancellationToken场景。

验证捕获逻辑

测试时,调用目标方法后,可以通过Mock的Logger验证LogError是否被调用,确认异常被正确捕获:

// 假设你Mock了ILogger
var logger = new Mock<ILogger<YourService>>();

// 初始化你的服务,传入Mock的factory和logger
var service = new YourService(factory.Object, logger.Object);

// 调用目标方法
await service.YourMethodThatCallsGetAsync();

// 验证LogError是否被调用
logger.Verify(
    x => x.LogError(
        It.IsAny<Exception>(),
        It.IsAny<string>()
    ),
    Times.Once
);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 19:30:03