Reputation: 263
For C#'s Moq, I went in through debugger, and noticed It.IsAny<T>()
just compiles to a certain value of T
, like Guid.Empty
for Guid
s, 0 for int
s, etc.
How does Moq tell the difference between an It.IsAny<T>
and the value that it compiles to?
Upvotes: 6
Views: 1913
Reputation: 61932
The lambdas we use when we Setup
mocks in Moq are not the usual delegates, they are expression trees. The It.Is<>
method is just a place-holder. It is not necessarily actually called. It is not important if it returns default(T)
or just throws a NotSupportedException
or something else. Let me give an example:
interface IMyFace
{
void MethodToTest(object obj);
}
static class Test
{
public static void Main()
{
Setup<IMyFace>(x => x.MethodToTest(null));
Setup<IMyFace>(x => x.MethodToTest(MyAnyA<object>()));
Setup<IMyFace>(x => x.MethodToTest(MyAnyB<object>()));
}
public static TArg MyAnyA<TArg>()
{
// never runs
return default(TArg);
}
public static TArg MyAnyB<TArg>()
{
// never runs
return default(TArg);
}
public static void Setup<T>(Expression<Action<T>> expr) where T : class
{
Console.WriteLine("The expr was: " + expr);
}
}
Not too interesting, but it should show that with expression trees Expression<...>
you can see what method was used, and not just the returned value. Find out more on how to examine an expression tree on MSDN, Expression Trees.
Upvotes: 7
Reputation: 26347
Taking base in the GitHub source code, what's really being matched is a given predicate of type Predicate<T>
(or Func<T, bool>
if you like):
value => value == null || typeof(TValue).IsAssignableFrom(value.GetType())
It checks if the value
is null, or if the value
is the same type as the TValue
argument for IsAny<TValue>
using Type.IsAssignableFrom.
It then returns the default(T)
value of the type to allow the mocked method to correctly match the signature. And as pointed out by DavidH, you can't use null for value types, which is why using default(T) is preferred as a generic return value.
Upvotes: 7