HowTo: Mock a Linq-based Dao

I will try to explain a way to mock a linq based Dao, as the one introduced by Fabio Maulo here. The interface of the dao is something like this:

public interface IDao<TEntity{
//....
IEnumerable<TEntity> Retrieve(Expression<Func<TEntity, bool>> predicate);

int Count(Expression<Func<TEntity, bool>> predicate);
}

Suppose you have a controller or service, and you want to test a method is using a proper predicate for load the invoices of a given month and year. I’m using Moq for this example:

daoInvoices
    .Setup(dao => dao.Retrieve(Par.IsAnyPredicateOf<Invoice>()))
    .Returns(new List<Invoices> {newInvoice})
    .Callback<Expression<Func<Invoice, bool>>>(
predicate =>
    {
        predicate.Evaluate(invoiceIn)
                .Should().Be.True();

        predicate.Evaluate(invoiceOut)
                .Should().Be.False();
    }
);

Why I’m doing this?, Why validate the predicate in the callback? Because you can't match Expressions . You can read more info here, Moq isn’t exempt of this fact. So, my mock ignores the parameter, but the parameter is checked in the callback.

Evaluate(..) is an extension method for Expressions:

public static class ExpressionsExtensions
{
    public static bool Evaluate<T>(this Expression<Func<T,bool>> expression, T value)
    {
        return expression.Compile()(value);
    }
}

the expression is compiled twice, so?..
Par.IsAnyPredicateOf is another helper:

public static class Par
{
    public static Expression<Func<T, bool>> IsAnyPredicateOf<T>()
    {
        return It.IsAny<Expression<Func<T, bool>>>();
    }
}

"It" comes from Moq.

And maybe this is out of topic but I’m not testing the query itself!!!!!!!!. The query should be tested against the database, and if is possible, the real one. I tend to define my queries in a separated place, so queries are declared as follows:

namespace MyXYZSuperProject.Domain.Predicates
{
    public static class Invoice
    {
        public static Expression<Func<Invoice, bool>> 
                        ByPeriod(int month, int year)
        {
            return invoice => 
                            invoice.Month == month 
                            && recupero.Year == year;
        }
    }
}

Month and year are stored properties in this case, be careful.
AND I didn’t say NHibernate in the whole post!


blog comments powered by Disqus
  • Categories

  • Archives