Comparing Simple Lambda Expressions With Moq

I was contacted today by a friend who was asking a very poignant question about using Moq in order to mock out a repository that uses expressions as finders. I don’t think they were using them quite like we are going to use them below, but I’m generalizing the problem to a certain extent.

The Setup

So we will start off with a simple Person class that looks like this:

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

Then let’s pretend that we have a repository with a "Find" method that looks like this:

public class PersonRepository: IPersonRepository
{
    private PeopleContext context = new PeopleContext();

    public IEnumerable<Person> Find(Expression<Func<Person,bool>> predicate)
    {
        return context.Where(predicate);
    }
}

Now this repository is very simple, and the single find method just takes an expression which can be used to filter and passes it onto to some IQueryable provider to do a query. But now we have a service somewhere else that calls into this repository like so:

public class PersonService
{
    private readonly IPersonRepository repository;

    public PersonService(IPersonRepository repository)
    {
        this.repository = repository;
    }

    public IEnumerable<Person> FindAllJustins()
    {
        return repository.Find(p => p.FirstName == "Justin");
    }

    public IEnumerable<Person> FindAllEtheredges()
    {
        return repository.Find(p => p.LastName == "Etheredge");
    }
}

Now the repository is just being passed into the service via the constructor, and it uses the repository’s interface so we can easily mock this out, right? Well, that depends on what we want to do. If we mock out the repository, then how do we tell if we are calling the Find method with a lambda that is comparing first name or last name? What if we wanted to return different data for these?

The Ideal

In order to start to come close to a solution we need to first figure out what the ideal syntax in Moq would be for us to perform something like this:

var mock = new Mock<IPersonRepository>();

mock.Setup(r => r.Find(p => p.FirstName == "Justin")).Returns(new []
    {
        new Person {FirstName = "Justin", LastName = "Smith"},
        new Person {FirstName = "Justin", LastName = "Quincy"}
    });

mock.Setup(r => r.Find(p => p.LastName == "Etheredge")).Returns(new[]
    {
        new Person {FirstName = "Bob", LastName = "Etheredge"},
        new Person {FirstName = "Stewart", LastName = "Etheredge"}
    });

Okay, that looks good, but it won’t work. Unfortunately Moq won’t accept the lambda expression there, and even if it did, there wouldn’t be any easy way to compare it later to the expression inside of the repository since expressions are not directly comparable except by reference.

The Start Of A Solution

So the first thing we need to do is figure out how we can control the comparison of these items by Moq. In order to do this we need to leverage a feature in Moq called custom matchers. In Moq 3.0 they introduced a greatly simplifed syntax for this:

public static string AreEqual<T>(string val1)
{
    return Match<string>.Create(val2 => val1 == val2);
}

This is a custom matcher that would compare strings, but that isn’t exactly useful to us since Moq will already do this. What we need to do is implement a matcher that can compare expression trees. But expression trees can’t be easily compared. One way might be to implement a walker that would walk two expression trees comparing nodes and tell us if two trees are equal, but that would be really hard and would likely end up with a bunch of edge cases.

A Flawed, But Quick, Solution

Now, I was googling around to try and find a solution to comparing expression trees and I found a Stack Overflow post where Marc Gravell had suggested comparing the strings that are spit out of the expression trees. I’ve compared them many a time manually, seems easy enough. Now, that will only work in simple expressions, but in many cases that would likely be enough! So, let’s look at how we would implement the custom matcher for this:

public static Expression<Func<T,bool>> AreEqual<T>(Expression<Func<T,bool>> expr)
{
    return Match<Expression<Func<T, bool>>>
        .Create(t => t.ToString() == expr.ToString());            
}

So it just takes our two expression trees and converts them to strings and compares the results. And you know what, when we setup like this:

mock.Setup(r => r.Find(AreEqual<Person>(p => p.FirstName == "Justin"))).Returns(new []
    {
        new Person {FirstName = "Justin", LastName = "Smith"},
        new Person {FirstName = "Justin", LastName = "Quincy"}
    });

And use it like this:

var personService = new PersonService(mock.Object);
var justins = personService.FindAllJustins();

It works perfectly! We get back exactly the list that we expected.

Summary

Now this is far from a perfect solution, but it does get us far enough where we can test scenarios where we might need the repository to return more than one set of items. Let me know if you get a chance to use this, and any issues that you might run into! In the future I might look into how we could write code to more thoroughly compare expression trees, but there will always be trees which aren’t comparable.

Be Sociable, Share!

8 comments

  1. Alternatively, couldn’t you evaluate the expression against some mock data and make sure you get the right answer back? Something like:

    mock.Setup(r => r.Find(p => p.FirstName == "Justin")).Returns((Expression<Func<Person,bool>> predicate) => testData.Find(predicate));

  2. @Graham Excellent idea, you could use another fake data store and then execute the expression against it. The downside is that you would still need to match the expression inside the "Setup" delegate in the same way as in the post. Your code above would not work because Moq cannot match the expression to the one being passed in.

    But yes, instead of returning a static set of data for each call, we could compile the expression and execute it against a data store in order to return our fake results.

  3. Kevin Dente pointed me at the IQueryable Toolkit on CodePlex, which has an ExpressionComparer (http://www.codeplex.com/IQToolkit). It does the whole expression visitor thing to walk the expression tree and compares individual nodes. Not as simple as ToString(), but it works nonetheless.

  4. @Jimmy Thanks, I had found a few examples of doing that, and now that you have found one in a project with an MS-PL license I will probably put up a post about it. Thanks! I would much rather do the comparison by walking the tree, because that would obviously lead to a more accurate comparison.

  5. Another approach is you could encapsulate all of your expression tree’s in a IQuery that would expose the expression tree. That way you could assert that your service would call the Repository with a specific query object:

    _repositoryMock.Expect(x => x.Find(It.Is<FindByEmailQuery<Account>>(q => q.Email.Equals(_email)))).Returns(_account).AtMostOnce();

    Although this adds another layer of objects and complicates it more, but going this route is a little better for encapsulation.

    Nate went this route when creating Zelda that has some good examples among other blogs and such: http://code.google.com/p/zelda/

  6. Would you happen to know how to do that in Rhino.Mocks?

  7. @Peter Apologies, but I haven’t used Rhino in a while and so I’m not familiar enough to write it out for you.

  8. Have you followed up the implementaion using the IQueryable Toolkit ? I’d be very interested in the solution.

Leave a comment