.NET Core 3.1 XUnit测试本地通过 Azure DevOps报Json反序列化错误
问题排查步骤
- 第一步:先补全请求状态校验,同时打印Azure环境下的接口实际返回内容
你当前代码没有判断查询接口的请求是否成功,直接读取返回内容反序列化。可以在反序列化前加入代码:Assert.True(response.IsSuccessStatusCode, $"查询接口请求失败,状态码:{response.StatusCode},返回内容:{responseString}"),运行Azure DevOps测试后从日志中提取返回的实际内容,确认是不是异常时返回的错误对象(比如ASP.NET Core默认的ProblemDetails结构)、或者加了全局响应包装的结构、或者接口返回结构从数组改成了单个对象。
注意:你本地调试时贴出的responseString是HttpResponseMessage的ToString结果,不是接口实际返回的业务JSON,说明你本地调试时看错了返回内容,这个结构本身就不是数组,反序列化本来就会失败,说明你本地可能是因为接口实际返回内容和你看到的不一致才跑通 - 第二步:检查
/api/Campaign/find?title=Test接口的逻辑
确认接口有没有兼容无匹配数据的场景:如果没有匹配的Campaign时接口返回了单个null、NotFound对象,而不是空数组[],就会触发反序列化错误。另外确认是不是Azure环境的接口版本和本地不一致,返回结构从数组改成了单个对象。 - 第三步:检查Azure环境的中间件配置
确认是不是加了全局响应包装中间件,把所有接口返回都包成了{code:200, data:[], msg:"success"}这类结构,你直接反序列化外层对象自然会失败,本地没加这类中间件所以能正常跑通。
解决方案
- 调整测试代码,补全校验逻辑,示例如下:
[Fact] public async Task RemoveCampaign_RemoveOneCampaignIsSuccessWhenCampaignIdIsValid() { var client = _factory.CreateClient(); var response = await client.GetAsync("/api/Campaign/find?title=Test"); var responseString = await response.Content.ReadAsStringAsync(); // 提前校验请求状态,出错直接打印返回内容 Assert.True(response.IsSuccessStatusCode, $"查询接口异常,返回内容:{responseString}"); List<CampaignResponseDto> resultList; try { resultList = JsonConvert.DeserializeObject<List<CampaignResponseDto>>(responseString); } catch (JsonSerializationException ex) { // 序列化失败时抛出详细信息方便排查 throw new InvalidOperationException($"反序列化失败,实际返回内容:{responseString}", ex); } var result = resultList.FirstOrDefault(); Assert.IsType<CampaignResponseDto>(result); if (result != null) { var deleteResponse = await client.DeleteAsync($"/api/Campaign/{result.Id}"); // 修复原来的断言错误:你之前写的是校验查询请求的状态,应该校验删除请求的状态 Assert.True(deleteResponse.IsSuccessStatusCode); Assert.Equal(HttpStatusCode.Accepted, deleteResponse.StatusCode); } }
- 如果排查发现Azure环境加了全局响应包装,定义对应的包装类,先反序列化包装类再取数据字段的数组即可。
- 如果是接口无匹配数据时返回结构不统一,调整接口逻辑,无数据时统一返回空数组
[]即可。
内容的提问来源于stack exchange,提问作者Steve
相关产品推荐
相关产品推荐

