C#单元测试如何验证HttpClient的PostAsync调用及传入参数正确性
实现单元测试的解决方案
现有代码问题
你当前无法测试PostAsync调用的核心原因是方法内部直接实例化HttpClient,没有对外暴露依赖入口,无法替换为模拟对象捕获调用记录。同时每次在方法内using创建HttpClient属于不推荐实践,会频繁占用释放端口,容易引发资源耗尽问题。
第一步:改造业务代码解耦依赖
先调整业务类,将HttpClient通过构造注入,为后续单元测试替换模拟对象提供入口:
public class YourRestServiceClass { private readonly HttpClient _httpClient; public YourRestServiceClass(HttpClient httpClient) { _httpClient = httpClient ?? throw new ArgumentNullException(nameof(httpClient)); } public async Task<HttpResponseMessage> MakeRestCallAsync(Uri uri, string input) { using (var formData = new MultipartFormDataContent()) { formData.Add(new StringContent(input), "Input"); return await _httpClient.PostAsync(uri, formData); } } }
第二步:编写单元测试
你可以通过Moq框架模拟HttpMessageHandler(HttpClient底层发送请求的核心类),拦截并校验所有请求参数:
前置依赖
你需要提前安装NuGet包:Moq、Microsoft.VisualStudio.TestTools.UnitTesting
测试代码示例
using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; using Moq.Protected; using System.Net; using System.Net.Http; using System.Threading; using System.Threading.Tasks; [TestClass] public class RestServiceTests { [TestMethod] public async Task MakeRestCallAsync_Should_Call_PostAsync_With_Expected_Parameters() { // 定义预期参数 var expectedUri = new Uri("https://test.example.com/api"); var expectedInput = "test_input"; Uri actualRequestUri = null; string actualInputValue = null; // 模拟HttpMessageHandler,拦截请求 var mockHandler = new Mock<HttpMessageHandler>(); mockHandler.Protected() .Setup<Task<HttpResponseMessage>>( "SendAsync", ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>() ) .ReturnsAsync(new HttpResponseMessage(HttpStatusCode.OK)) .Callback<HttpRequestMessage, CancellationToken>(async (request, _) => { // 捕获实际请求的URI actualRequestUri = request.RequestUri; // 解析表单内容获取Input参数 if (request.Content is MultipartFormDataContent formContent) { foreach (var part in formContent) { if (part.Headers.ContentDisposition.Name == "\"Input\"") { actualInputValue = await part.ReadAsStringAsync(); break; } } } }); // 构造测试用的HttpClient和业务类实例 var testHttpClient = new HttpClient(mockHandler.Object); var service = new YourRestServiceClass(testHttpClient); // 执行测试方法 await service.MakeRestCallAsync(expectedUri, expectedInput); // 校验结果 // 校验Post请求确实发送了1次 mockHandler.Protected().Verify( "SendAsync", Times.Once(), ItExpr.Is<HttpRequestMessage>(r => r.Method == HttpMethod.Post), ItExpr.IsAny<CancellationToken>() ); // 校验请求URI正确 Assert.AreEqual(expectedUri, actualRequestUri); // 校验提交的Input参数正确 Assert.AreEqual(expectedInput, actualInputValue); } }
内容的提问来源于stack exchange,提问作者Polina F.
相关产品推荐
相关产品推荐

