Verifications
When writing unit tests for components consuming dependencies, it's important to make sure the right calls were invoked on the dependencies.
Moq has built-in support for tracking invocations: it leverages the same argument matching syntax used for configuring methods to filter invocations. When inspecting invocation, developers can even assert the expected count.
The snippets in this section will be based on the following interface
Implicit verification
The easiest way to verify that the calls configured on mocks were actually performed is by using the Verifiable
construct at the end of each configuration.
Later, we can use the VerifiyAll
to verify that all configurations enriched with Verifiable
were matched by an invocation.
Optionally, developers can customize the fail message outputted by Moq if the verification were to fail.
If your unit test uses multiple mocks, you can use Mock.Verify
to verify all verifiable configuration at once.
Explicit verification
Another approach is to explicitly verify that a certain invocation was performed. While more verbose, it offers more powerful tools to developers.
The Verify
method offers additional overloads to specify the fail message and the amount of times the invocation was expected to be performed. The amount of times can be specified as a known value or via a lazily evaluated expression.
Note that since Verify
accepts both Times
and Func<Times>
, both Times.AtLeastOnce()
and Times.AtLeastOnce
are accepted by the compiler.
Times
The Times
class exposes several factory methods to define the constraint on amount of invocations as needed. The basic methods are
Exactly
: the constraint will fail if the configuration isn't used the specified amount of timesAtLeast
: the constraint will fail if the configuration is used for a number of time less than the specified amountAtMost
: the constraint will fail if the configuration is used for a number of time greater than the specified amountBetween
: the constraint will fail if the configuration is used a number of times outside of the specified intervalOn top of these methods, there are other helpers that can be used to streamline the creation of constraints
Never
: the constraint will fail if the configuration is used at least onceOnce
: the constraint will fail if the configuration is not used or used more than onceAtLeastOnce
: the constraint will fail if the configuration is never usedAtMostOnce
: the constraint will fail if the configuration is used more than once. Note that no usage is also valid for the constraint.
Verifying calls on properties
Like for methods, Moq supports the verification of matching invocations for properties. Developers can configure implicit verification
Alternatively, developers can explicitly verify the performed invocations.
Finally, Verifiable
, VerifyGet
and VerifySet
offer an overload to specify a custom message to return in case the constraint fails.
Implicit or explicit verification?
Moq supporting two different styles of verification makes room for making unit tests either unnecessarily tight or dangerously open. The agency offered by Moq consolidates in two approaches
Open configuration, close verification
Close configuration, open verification
When following the first approach, developers should configure methods and properties relying as much as possible on constructs like It.IsAny
. In the Assert section of the unit test, developers should then rely on explicit verification with constraints as specified as possible.
On the other hand, when following the second approach, developers should configure methods and properties specifying as much as possible the expected parameters and rely on implicit verification.
Please note that the two approaches are not exactly equivalent as implicit verification does not support checking the amount of invocations.
As mentioned above, using the remaining two approaches (open/open and close/close) is suboptimal when not dangerous. The open/open approach below makes the verification almost useless.
The close/close approach below makes writing the unit test too cumbersome for no real gain
Verifying event handling
When dealing with events, it's important to make sure that events are properly handed both to ensure the component works as expected.
Similarly, registered events should be unregistered to avoid annoying memory leaks.
Moq offers the possibility to set expectations on both registration and unregistration of event handler.
Last updated