单元测试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
相关产品推荐
相关产品推荐

