如何使用Moq根据参数Mock两个不同的API POST请求?
如何Mock带StringContent参数的POST API调用并区分有效/无效ID
需求背景
需要Mock外部POST类型的API调用,分别测试传入有效ID(如1)和无效ID(如-1)时的代码逻辑,当前API参数以StringContent形式传递,且所有Mock逻辑集中在一个扩展类中。
核心解决方案
要区分不同的documentId,关键是在Mock的条件判断中解析POST请求的StringContent内容,提取出documentId后再做匹配判断。
1. 添加请求内容解析的辅助方法
先写一个工具方法,从HttpRequestMessage中读取并解析出documentId:
private static int? GetDocumentIdFromRequest(HttpRequestMessage request) { if (request.Content is not StringContent stringContent) return null; // 测试场景下同步读取内容,避免异步表达式树的问题 var contentJson = stringContent.ReadAsStringAsync().GetAwaiter().GetResult(); var payload = JsonSerializer.Deserialize<dynamic>(contentJson); return payload?.documentId?.Value; }
2. 分别配置有效/无效ID的Mock逻辑
修改集中管理的MockApiCalls方法,添加两个不同条件的Mock分支:
private static void MockApiCalls(Mock<HttpMessageHandler> mock) { // Mock 有效ID(1)的响应:返回成功结果 mock.Protected() .Setup<Task<HttpResponseMessage>>("SendAsync", ItExpr.Is<HttpRequestMessage>(e => e.Method == HttpMethod.Post && e.RequestUri.ToString().Contains("/api/GetDocInfo") && GetDocumentIdFromRequest(e) == 1), ItExpr.IsAny<CancellationToken>()) .ReturnsAsync(new HttpResponseMessage(HttpStatusCode.OK) { Content = new StringContent(JsonSerializer.Serialize(new { /* 填入业务侧预期的成功响应结构 */ }), Encoding.UTF8, "application/json") }); // Mock 无效ID(-1)的响应:返回错误结果 mock.Protected() .Setup<Task<HttpResponseMessage>>("SendAsync", ItExpr.Is<HttpRequestMessage>(e => e.Method == HttpMethod.Post && e.RequestUri.ToString().Contains("/api/GetDocInfo") && GetDocumentIdFromRequest(e) == -1), ItExpr.IsAny<CancellationToken>()) .ReturnsAsync(new HttpResponseMessage(HttpStatusCode.NotFound) { Content = new StringContent(JsonSerializer.Serialize(new { Message = "无效文档ID" }), Encoding.UTF8, "application/json") }); }
3. 编写对应的测试用例
在测试类中补充无效ID的验证方法:
[Test] public async Task ShouldReturnNotFoundForInvalidDocument() { var request = new GetInfoQuery(-1); var result = await SendAsync(request); Assert.NotNull(result); Assert.False(result.IsSuccess); // 可额外验证错误信息是否符合预期 }
注意事项
- 解析Content时使用
GetAwaiter().GetResult()是因为表达式树中无法直接使用await,测试场景下同步读取是安全的 - 确保JsonSerializer的配置和业务代码中的序列化配置一致,避免反序列化失败
- 如果需要覆盖更多ID场景,只需在
MockApiCalls中新增对应条件的Mock分支即可
内容的提问来源于stack exchange,提问作者Sergio
相关产品推荐
相关产品推荐

