'Moq - Is it possible to specify in a Setup the Verify criteria (e.g. Times called)?
If you need to Setup a return value, as well as Verify how many times the expression was called, can you do this in one statement?
From what I can gather, Moq's Setup(SomeExpression).Verifiable() called along with Verify(), basically does a Verify(SomeExpression, Times.AtLeastOnce)? i.e. it verifys the expression was called only.
Here's an example to explain the question better. For an interface:
interface IFoo
{
int ReturnSomething();
}
Are the following two blocks equivalent (other than the first will Verify all setups marked as verifiable)?
void Test()
{
var mock = new Mock<IFoo>();
mock.Setup((m) => m.ReturnSomething()).Returns(1).Verifiable();
mock.Verify();
}
and
void Test()
{
var mock = new Mock<IFoo>();
mock.Setup((m) => m.ReturnSomething()).Returns(1);
mock.Verify((m) => m.ReturnSomething(), Times.AtLeastOnce());
}
If I wanted to verify the number of calls (say twice), is this the only way, where the expression is repeated for the Setup and Verify?
void Test()
{
var mock = new Mock<IFoo>();
mock.Setup((m) => m.ReturnSomething()).Returns(1);
mock.Verify((m) => m.ReturnSomething(), Times.Exactly(2));
}
I just don't like having to call Setup and Verify. Well, since this is a good idea for AAA, to rephrase, I don't like having to repeat the expression for the Setup and Verify. At the moment I store the expression in a variable and pass it to each method, but doesn't feel so clean.
PS - The context for this is for a test checking when a cache is updated or not (expirations etc.)
Solution 1:[1]
I have this problem all the time. I use strict mocks, and I want to specify strictly (i.e. I used It.Is<>() instead of It.IsAny()) as well as verify strictly (i.e. specifying Times). You cannot use verifiable for this sadly, because Moq is missing a Verifiable(Times) overload.
The full expression of the call, including It.Is<>() is generally big. So in order to avoid duplication I generally resort to the following:
Expression<Action<MockedType>> expression = mockedTypeInstance => mockedTypeInstance.MockedMethod(It.Is<TFirstArgument>(firstArgument => <some complex statement>)/*, ...*/);
_mock.Setup(expression);
/* run the test*/
_mock.Verify(expression, Times.Once);
Not extremely readable, but I don't think there is another way to both use strict setup and strict verification.
Solution 2:[2]
To answer the first question, yes the two blocks are equivalent. Both will fail when .Verify is called if the method on the mock wasn't called.
You can't specify the verify up front as far as I am aware and if you think about it, it makes sense.
This is specifying the behavior of the mock:
mock.Setup(m => m.ReturnSomething()).Returns(1);
This is verifying the behavior of the caller:
mock.Verify(m => m.ReturnSomething(), Times.AtLeastOnce());
Personally I prefer calling verify individually to confirm the required behavior of the caller, the .Verifiable() and .Verify() are shortcuts that are less strict (they just check the method was called one or more times) however if you know your code should only call a method once, put the verify in at the end to confirm it.
I started doing that after a code merge resulted in a method being called twice, the test still passed since it was called at least once but it also meant that something else happened multiple times which shouldn't have!
Solution 3:[3]
Expounding on the answer by Evren Kuzucuoglu, I created the following extension methods to make creating the expressions a little simpler:
/// <summary>
/// Creates a method call expression that can be passed to both <see cref="Setup"/> and <see cref="Verify"/>.
/// </summary>
/// <typeparam name="T">Mocked object type.</typeparam>
/// <param name="mock">Mock of <see cref="T"/>.</param>
/// <param name="expression">Method call expression to record.</param>
/// <returns>Method call expression.</returns>
public static Expression<Action<T>> CallTo<T>(this Mock<T> mock, Expression<Action<T>> expression) where T : class
{
return expression;
}
/// <summary>
/// Creates a method call expression that can be passed to both <see cref="Setup"/> and <see cref="Verify"/>.
/// </summary>
/// <typeparam name="T">Mocked object type.</typeparam>
/// <typeparam name="TResult">Method call return type.</typeparam>
/// <param name="mock">Mock of <see cref="T"/>.</param>
/// <param name="expression">Method call expression to record.</param>
/// <returns>Method call expression.</returns>
public static Expression<Func<T, TResult>> CallTo<T, TResult>(this Mock<T> mock, Expression<Func<T, TResult>> expression) where T : class
{
return expression;
}
Usage example:
var createMapperCall = mockMappingFactory.CallTo(x => x.CreateMapper());
mockMappingFactory.Setup(createMapperCall).Returns(mockMapper.Object);
mockMappingFactory.Verify(createMapperCall, Times.Once());
Solution 4:[4]
I created a utility class that takes care of this:
public class TestUtils
{
private static List<Action> verifyActions = new List<Action>();
public static void InitVerifyActions() => verifyActions = new List<Action>();
public static void VerifyAllSetups()
{
foreach (var action in verifyActions)
{
action.Invoke();
}
}
public static ISetup<T> SetupAndVerify<T>(Mock<T> mock, Expression<Action<T>> expression, Times times) where T : class
{
verifyActions.Add(() => mock.Verify(expression, times));
return mock.Setup(expression);
}
public static ISetup<T, TResult> SetupAndVerify<T, TResult>(Mock<T> mock, Expression<Func<T, TResult>> expression, Times times) where T : class
{
verifyActions.Add(() => mock.Verify(expression, times));
return mock.Setup(expression);
}
}
Then in TestInitialize(), I call TestUtils.InitVerifyActions(), and in the unit tests:
TestUtils.SetupAndVerify(myMock, m => m.Foo("bar"), Times.Once()).Returns("baz");
TestUtils.SetupAndVerify(myOtherMock, m => m.Blah(), Times.Once());
...
TestUtils.VerifyAllSetups();
Solution 5:[5]
While far from enough Moq indeed has the AtMost() and AtMostOnce() methods on the Setup call, however it is marked as Obsolete, but it appears to be a mistake according to this GitHub issue
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | Trevor Pilley |
| Solution 3 | Jack A. |
| Solution 4 | DSoa |
| Solution 5 | yoel halb |
