Method calls
Most of the times, Moq will be used to mock service interfaces and their methods. Moq offers several utilities to properly configure method calls.
As shown earlier, methods can be configured using the Setup method. Additionally, developers can configure sequences of calls. Finally, Moq supports the configuration of methods with less common arguments such as reference parameters, out parameters and optional arguments.
Single calls
Using the Setup
method, developers can configure method calls on mocks by leveraging the different argument match techniques shown earlier.
When a mock is configured like above, it will react to any call matching the incoming parameters (any string, in the example).
Setup
also supports asynchronous methods.
Repeated calls
Sometimes, we need to configure the mocks so that their methods have different outcomes when called repeatedly.
When a mock is configured like above, repeated calls will receive the specified result in sequence. (Returns
will be explained more in details later).
In case the configured method has no return type, Pass can be used to configure an uneventful invocation.
Calls in sequence
Another scenario supported by Moq is the one of setting up calls in sequence, across different methods and even across different mocks. To be able to properly verify the calling sequence, it's best to set the mocks using the strict mode, more information on this in the advanced section of this guide.
To properly configure sequences, developers need to create an instance of MockSequence and bind the mocks to it.
In the first example we are configuring the mock of a service to respond to calls to a method with an exact sequence of parameters
In the second example, we're configuring a sequence of calls of different methods belonging to the same mock
Finally, in the third example, we're configuring a sequence of calls across different mocks
When calls are configured within a sequence, Moq will not recognize calls out of sequence and, if operating in strict mode, will throw exceptions for non-configured calls.
Please notice how all mocks are created specifying the parameter MockBehavior.Strict
. More information on the concept of mock behavior later.
Parameters passed by reference
Normally, when invoking a method, references to objects are passed by value. This means that the method cannot change the target of the incoming variable. Sometimes this behavior is not desirable and for this reason developers can pass object references by reference to methods. This is achieved by using the ref
keyword when declaring your method's arguments. Here is a page on the official documentation regarding passing reference-type parameters by reference.
Moq gives the developer the possibility to easily work with "ref parameters". Developers can specify that the method should respond to a specific instance
Alternatively, they can specify that a specific instance must be passed to the method, and returned to the caller.
Finally, although requiring some extra work, developers can customize the referenced object after the method is invoked.
When DoSomething
is invoked, the variable holding the reference to the passed argument will be holding a reference to the newValue
variable.
The setup is a bit more convoluted here. The reason is that C# doesn't support Action
and Func
delegates with ref parameters: to obviate this issue, we define a custom delegate and we use it to create a callback function that Moq will invoke when the method is invoked. We will look at how Moq supports callbacks later.
Out parameters
Similarly to ref parameters, out parameters are used to pass values by reference. Here is a page on the official documentation regarding out parameters.
Developers can specify that a specific instance must be returned to the caller
When DoSomething
is invoked, the out parameter will be a reference to the preset variable: in the example, the variable value
.
Optional arguments
Optional arguments were introduced in C# 4.0. This functionality gives developers the possibility to mark some parameters of a method as optional by providing a default value. This means that the same method can be invoked with a varying list of parameters.
In the example below, the method DoSomething can be invoked either by passing any string or by leveraging the given default value.
When mocking interfaces or classes that expose methods with optional arguments, it's important to remember to specify a value for the optional arguments.
Probably the most common case is the CancellationToken
to be provided to most asynchronous methods. As most libraries specify a default value for the CancellationToken
argument, developers often overlook the necessity to specify a value for that argument. In this case developers can either use the IsAny
construct or the default
keyword.
Please note that in the first case, we are accepting any CancellationToken
while in the latter, we're specifying a specific value. If the component under test were not to rely on the default value, Moq would not capture the invocation.
Last updated