The It.Is and It.IsAny methods of the Moq unit-testing framework and why your "partial mocking" might do not work

Unit-testing of existing code can sometimes be a challenge, since you have to deal with classes that contain too much of functionality. In that case the “Single Responsibility” principle was not in focus, however, refactoring the code can be an issue, so you will have to unit-test the class as it is. Apart from that we do not want to “mock” the Interface of a class, which would mock all its method, but the class it self.

Such classes are calling methods of the same class, so the task is to mock only few of the methods, but not all of them, since we also want to unit-test some of them. The feature of partially mocking the methods of a class is called partial mocking. The methods that we want to mock, have to be defined as virtual, so that Moq can ovveride them. This feature can be a sign of code smell, when overused.

There are some great examples in StackOverflow on how to achieve that, however, in this article I would like to focus on an issue that caused my partial mocks not to work and show you how I fixed it.

Here is a simple example of how the partial mocking works:

1
2
3
4
5
var mockedCustomer = new Mock<Customer>();
mockedCustomer.CallBase = true; // If true, calls the real method of the object, if this method was not mocked.

mockedCustomer.Setup(x => x.GetAddresses()).Returns(new List<Address>()); // This method is getting mocked
mockedCustomer.Object.GetAgeInYearsAndMonths(); // The real method is getting called

The problem I faced was that even though I mocked some of the class methods, the real implementations of these were getting called. After a lot of experimenting I found out that the It.Is method of Moq Framework was the issue to that problem. Consider the following example, in where the GetAddresses excepts a flag-string to get passed and this flag has to have a specific value:

1
mockedCustomer.Setup(x => x.GetAddresses(It.Is<string>(x => x == "privateAddresses")).Returns(new List<Address>());

The previous example was causing the mocked method not to get called, even when I was using the CallBase = true flag. When I refactored the code to use the It.IsAny method of Moq, then the mocked method worked! For that I had to do the check I did in It.Is inside the Returns method. I guess this issue has to do with the Func expression that gets passed into It.Is.

1
2
3
4
5
mockedCustomer.Setup(x => x.GetAddresses(It.IsAny<string>()).Returns<string>(s => {
  if (s == "privateAddresses") return new List<Address>());

  return null;
}

I hope you this article helped you, if you faced the same problem as I did. Any comments are welcome.

comments powered by Disqus