I have a test class invoking a mock of MyClass
, I've Setup
both DoStuffA
and DoStuffB
previously.
I've tried to wrap several Verify
calls within a method, like so:
void VerifyMany(int input)
{
_myClassMock.Verify(ic => ic.DoStuffA(input), Times.Once());
_myClassMock.Verify(ic => ic.DoStuffB(input), Times.Once());
}
If I call my method with It.IsAny<int>()
as the input - VerifyMany(It.IsAny<int>())
- my tests don't pass, it will however work if I call the Verify method directly with It.IsAny:
_myClassMock.Verify(ic => ic.DoStuffA(It.IsAny<int>()), Times.Once());
_myClassMock.Verify(ic => ic.DoStuffB(It.IsAny<int>()), Times.Once());
I understand from the answer to this question that Moq handles It.IsAny differently within an expression when specified to Setup/Verify, is there any workaround for this?
The reason this doesn't work:
void VerifyMany(int input)
{
_myClassMock.Verify(ic => ic.DoStuffA(input), Times.Once());
_myClassMock.Verify(ic => ic.DoStuffB(input), Times.Once());
}
Is because It.IsAny<int>()
(when simply invoked) returns 0. So essentially when VerifyMany
is called with It.IsAny<int>()
, you're passing 0 to VerifyMany
. Which in turn means DoStuffA(0)
and DoStuffB(0)
are verified (not Any integer value as you probably intended it).
The other invocation:
_myClassMock.Verify(ic => ic.DoStuffA(It.IsAny<int>()), Times.Once());
_myClassMock.Verify(ic => ic.DoStuffB(It.IsAny<int>()), Times.Once());
Does work because the ic => ic.DoStuffA(It.IsAny<int>()
part is never directly invoked. It is turned into an Expression Tree and Moq only walks (or visits if you like) that Expression Tree. Which means it will find It.IsAny<int>()
in the Expression Tree and is then able to verify a call to DoStuffA
(which it also found in the same expression tree) with any integer value. (for more on expression trees, feel free to read this)
You could make this semi-work by creating a method which abstracts the call to Verify
away and accepts an expression like so:
void VerifyOnce(Expression<Action<ClassMockIsBasedOn>> callToVerify)
{
_myClassMock.Verify(callToVerify, Times.Once());
}
Which allows you to call that like so:
VerifyOnce(ic => ic.DoStuffA(It.IsAny<int>())
You could also extend the VerifyOnce
example to accept multiple expressions. That would allow you to verify DoStuffA
and DoStuffB
on a single line:
void VerifyOnce(params Expression<Action<ClassMockIsBasedOn>>[] callsToVerify)
{
foreach(var callToVerify in callsToVerify)
{
_myClassMock.Verify(callToVerify, Times.Once());
}
}
That would allow a call like so:
VerifyOnce(ic => ic.DoStuffA(It.IsAny<int>(),
ic => ic.DoStuffB(It.IsAny<int>());
And of course you could replace ClassMockIsBasedOn
with a generic. And add an overload which allows for methods which return values (instead of being void) or accept more than one parameter as Brett suggested in the comments.
It.IsAny
only allows Moq to match future invocations of method calls if used within the Setup
construct, you can't do it with Verify
or Assert
if your Setup
isn't set It.IsAny
yet. Because It.IsAny
always return a default value of input.
So if you want to use It.IsAny
at Verify
you should Setup
for target method first:
Correct
_myClassMock.Setup(ic => ic.DoStuffA(It.IsAny<int>())).Returns(// Something here);
_myClassMock.Verify(ic => ic.DoStuffA(It.IsAny<int>()), Times.Once());
Wrong
_myClassMock.Setup(ic => ic.DoStuffA(1)).Returns(// Something here);
_myClassMock.Verify(ic => ic.DoStuffA(It.IsAny<int>()), Times.Once());
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With