Writing Better Method Call Assertions in .NET

Stop Using Moq.Verify

Roko Kovač
3 min readNov 15, 2022

Introduction

In this blog post, I will show you the usual way of testing method calls, explain why using Moq.Verify is not ideal, and propose a different approach.

Get the full Quickstart Guide on Unit Testing in .NET here.

Unit tests

We can all agree on the benefits of testing.

For most developers, the biggest amount of testing will be done through unit tests.

Unit tests are an extremely powerful tool. They provide short feedback loops and force us to write our code in a more clean and isolated manner, thus making our codebase less error prone, easier to change, and overall, more maintainable.

Unit tests should help save time

As developers, it is our duty make our unit tests as readable and as helpful as possible so that the people who maintain and build upon our code can spend as much time solving business problems instead of fixing bugs, or worse, fixing tests.

Example

Consider the following example.

The Behaviour We’re Testing

We have a common CQRS flow in place with a SellItemCommand and the handler for that command. We want ensure the handler, in the event of the last item in stock being sold, publishes an ItemOutOfStock event to the event bus with the correct information.

The usual way

At the first glance, there seems to be nothing wrong with the test. It’s short, readable and the intent is clear.

However, let’s see what happens when the test fails. For the purpose of demonstration, I will make the handler publish a message with a different Reason.

We run the test, and see the following message:

Moq.MockException : 
Expected invocation on the mock at least once, but was never performed: x => x.Publish(It.Is<ItemOutOfStockEvent>(e => ((e.StoreId == 12 && e.ItemId == 12345) && e.Cashier == "Anna") && (int)e.Reason == 1))

Performed invocations:

Mock<IEventBus:1> (x):

IEventBus.Publish(ItemOutOfStockEvent)

This message is not very helpful. It tells you the test failed, but only tells you the method didn’t receive a call with the object it expected. This means you now have to debug the test, set a breakpoint, and manually check each property of the ItemOutOfStockEvent to find out which one of them is wrong. In addition, this whole exception message is a oneliner. Imagine the horror it would spew out when testing a complex object with dozens of properties.

A different approach

What I suggest instead, is to use Moq.Callback to store the method parameter and then assert each of the properties individually.

Let’s change our code to use this approach. I will also use FluentAssertions to improve readability.

Let’s try running the test now.

Expected publishedEvent.Reason to be StockoutReason.SoldOut {value: 1}, but found StockoutReason.LateDelivery {value: 2}.

That’s much better, isn’t it? The message clearly conveys why the test failed: The name of the property, what was the expected value and what was the actual value.

Final thoughts

Have you been writing tests using Verify? Will you give the Callback approach a go? Do you see any potential issues I missed? Let me know what you think.

If you’re interested in these kinds of topics, subscribe to get notified when I post more.

--

--