Better assertions when verifying Moq’d methods have been called

B

Moq, according to its GitHub page, is “The most popular and friendly mocking framework for .NET”.
Mocking frameworks allow you to create a ‘fake’ version of a dependency (typically an interface, or abstract class).
With this fake, you can then instruct the methods return values, or invoke behaviour.
Alternatively you can assert the methods were called, with a certain set of parameters.
How we verify these methods were called can affect the maintainability of our tests.

Let’s suppose we have this interface.

Which is a dependency of the class we’re testing:

Our method takes a firstName and lastName and creates a `Customer` object using those parameters.
It then passes that `Customer` object to the `Save` method on the injected ICustomerService.
For the purposes of our test, we inject a mocked `ICustomerService`
The `Save` method returns an int, so we set our mocked method to return 1, when it is called with any `Customer` object.

Our unit test could look something like this:

This test will of course pass. But, if we make a small change in our `CustomerController`

Now our test will correctly fail.
However the exact reason for the failure isn’t clear:

Moq.MockException :
Expected invocation on the mock at least once, but was never performed:  
x => x.Save(It.Is(c => c.FirstName == "Alex" && c.LastName == "Brown"))

All this tells us is that we didn’t call our dependency with an object that matches. It doesn’t give any indication as to why that object didn’t match.

Moq has a `Callback` function which we can use to assign our mocked `ICustomerService.Save` method to a variable outside of our setup.
Later on, we can use this variable for assertions.

And now, we can individually assert on each parameter:

If we run this test (without fixing our code from the previous failure) it now gives a much clearer failure:

Expected string length 5 but was 4. Strings differ at index 0.
Expected: "Brown"
But was: "Alex"
-----------^