在 CosmosDB 中模拟 ItemResponse

Mocking ItemResponse in CosmosDB

我正在 xUnit 中使用 Moq 为涉及 CosmosDB 的服务编写单元测试。有一个方法 GetVehicleInfo which returns ItemResponse<VehicleInfo> 来自 CosmosDB。由于 ItemResponse 有一个受保护的构造函数,所以我不能更新它。因此,我正在模拟调用方方法并执行

var responseMock = new Mock<ItemResponse<VehicleInfo>>();
responseMock.Setup(x => x.Resource).Returns(expectedItem); //expectedItem is of VehicleInfo type
cosmoRepoServiceStub.Setup(service => service.GetVehicleInfo("a1", "a2").Result).Returns(responseMock.Object);

我面临的问题是,当如下调用 GetVehicleInfo 时,它总是 returns null。我希望它 return ItemResponse<VehicleInfo> 其中 Resource 将包含 expectedItem.

ItemResponse<VehicleInfo> response = await _cosmosRepo.GetVehicleInfo(plate, country);
if (response == null){ //... }

您应该像这样设置您的 cosmoRepoServiceStub:

cosmoRepoServiceStub
    .Setup(service => service.GetVehicleInfo(It.IsAny<string>(), It.IsAny<string>()))
    .ReturnsAsync(responseMock.Object);
  • GetVehicleInfo参数应该是setup方法中的任意字符串
  • 与其在方法选择器中调用 .Result,不如使用 ReturnsAsync

或者如果您确实需要将 "a1" 作为第一个参数,则将其定义为

const StringComparison comparison = StringComparison.OrdinalIgnoreCase;
cosmoRepoServiceStub
    .Setup(service => service.GetVehicleInfo(
       It.Is<string>(param1 => string.Equals(param1, "a1", comparison), 
       It.Is<string>(param1 => string.Equals(param1, "a2", comparison)))
    .ReturnsAsync(responseMock.Object);

更新#1反映到评论

Why does It.IsAny work whereas "a1" does not?

Moq uses 在幕后使用 object.Equals 来检查 Setup 的参数与实际调用的参数。

这意味着值类型和字符串的比较是基于它们的值(而不是基于它们的引用)。

因此,在您的特定情况下,这意味着 platecountry 分别不包含 a1a2 字符串。

总之我应该工作,但根据一般经验

  • 让您的 Setup 尽可能通用
  • 让你的Verify尽可能具体