Home > database >  Mocking ItemResponse in CosmosDB
Mocking ItemResponse in CosmosDB

Time:02-11

I am writing unit tests using Moq in xUnit for a service that involves CosmosDB. There's a method GetVehicleInfo which returns ItemResponse<VehicleInfo> from CosmosDB. As ItemResponse has a protected constructor so I can't new it up. Therefore, I'm mocking the caller method and doing

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);

The problem I face is that when GetVehicleInfo is called as below, it returns null always. I expect it to return ItemResponse<VehicleInfo> wherein Resource will contain expectedItem.

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

CodePudding user response:

You should setup your cosmoRepoServiceStub like this:

cosmoRepoServiceStub
    .Setup(service => service.GetVehicleInfo(It.IsAny<string>(), It.IsAny<string>()))
    .ReturnsAsync(responseMock.Object);
  • GetVehicleInfo parameters should any string in the setup method
  • Instead of calling the .Result inside the method selector please prefer ReturnsAsync

Or if you really need to anticipate "a1" as a first argument then define it as

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);

UPDATE #1 Reflect to comment

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

Moq uses uses object.Equals under the hood to check the Setup's argument against the actual invocation's argument.

This means that the comparison for value types and for strings are based on their values (not based on their references).

So, in your particular case that means either plate or country does not contain a1 or a2 strings respectively.

In short I should work, but as a general rule of thumb

  • Make your Setup as generic as possible
  • Make your Verify as specific as possible
  • Related