Building lambda expressions at run time

September 23rd, 2009 by Andy Leave a reply »

Moq is a great library for creating fake objects for use in unit tests. It makes heavy use of lambda expressions to configure the mock, and also to verify that operations have been performed on the mock. For example, suppose we want to verify that the Insert method on an ICache interface has been called:

// Arrange 
var mockCache = new Mock<ICache>();
var someObject = new object();

// Act 
DoSomethingThatShouldAddObjectToCache(mockCache, someObject);

// Assert 
mockCalc.Verify( cache => cache.Insert(someObject) );

The key thing here is the use of a lambda expression in the Verify method. The lambda expression is just a convenient way to create a data structure specifying the method call we’re interested in (ICache.Insert) and the arguments we expect it to be called with (someObject). The Verify method is not going to execute the Insert method call – it’s merely going to examine the lambda expression structure to determine whether it matches a previous call on the mock (which the mock recorded in case we wanted to perform this type of verification).

The use of lambda expressions to package method names and arguments is a concise, typesafe and intellisense-friendly approach, but at first glance it appears to limit dynamic usage at run-time. An example of this problem was recently posted to the Moq discussion forum – the poster wanted to call mock.VerifyGet for every property on an interface, without having to write a VerifyGet call for every property individually.

Obviously reflection can be used to get the properties at runtime, but how do we build the appropriate lambda expression to pass to mock.VerifyGet()? Well, it turns out to be quite straightforward, using the LambaExpression class. The following code builds an expression of the type p => p.Prop, which is what we need for VerifyGet:

ParameterExpression p = Expression.Parameter(mockType, "p");
MemberExpression body = Expression.Property(p, prop);
LambdaExpression expr = Expression.Lambda(body, p);

Wrap this up in an extension method for the Mock<T> class, and we get the following VerifyAllGets() method:

public static void VerifyAllGets<T>(this Mock<T> mock) where T : class
{
    // Get a MethodInfo for the Mock<T>.VerifyGet<TProp> method.
    MethodInfo verifyGetMethod = typeof(Mock<T>).GetMethods(
        BindingFlags.Public | BindingFlags.Instance).Where(
        mi => mi.Name == "VerifyGet" &&
        mi.GetParameters().Length == 1).First();

    // Call the Mock<T>.VerifyGet method separately for each property on T.
    foreach (var prop in typeof(T).GetProperties())
    {
        // Build a lambda expression of the form p => p.Prop
        ParameterExpression p = Expression.Parameter(typeof(T), "p");
        MemberExpression body = LambdaExpression.Property(p, prop);
        LambdaExpression expr = LambdaExpression.Lambda(body, p);

        // Mock<T>.VerifyGet<TProp> must be 'closed' by specifying TProp
        var closedVerifyGetMethod = verifyGetMethod.MakeGenericMethod(prop.PropertyType);

        // Call Mock<T>.VerifyGet(expr)
        closedVerifyGetMethod.Invoke(mock, new object[] { expr });
    }
}

The VerifyAllGets() method can be used as follows:

// Arrange
var mock = new Mock<IManyProps>();

// Act
RunCodeThatGetsAllProps(mock);

// Assert
mock.VerifyAllGets();
Advertisement

Comments are closed.