Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How is Moq's It.IsAny<T>() implemented

Tags:

c#

moq

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 Guids, 0 for ints, etc.

How does Moq tell the difference between an It.IsAny<T> and the value that it compiles to?

like image 797
Anders Miltner Avatar asked Nov 17 '13 23:11

Anders Miltner


2 Answers

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.

like image 163
Claus Jørgensen Avatar answered Sep 25 '22 00:09

Claus Jørgensen


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.

like image 23
Jeppe Stig Nielsen Avatar answered Sep 27 '22 00:09

Jeppe Stig Nielsen