Moles and Linq to SQL: Mocking Linq to SQL Behavior

In recent years there’s been major investments in developing tools in order to provide good quality assurance features and incorporate industry practices into them.

TDD, DDD, Unit Testing, Continuous Integration, etc.

Microsoft has recently (not so recently actually :)) ship some very nice features to help us improve our code quality by allowing us to create better tests over units of code.

Unit testing is all about proving individual units of code (positive and negative testing). Since a great deal of software is not always designed with this “unit independence” in mind, it can be a challenge to isolate dependencies for every piece of source code (specially legacy code).

Moles is an Isolation Framework that mocks/emulates the behavior of our components and external libraries, even for private members. You could even mock how a particular System.* class object in .NET behaves (check Pex & Moles site in Microsoft Research).

The following is a Repository object that uses Linq to Sql Data Context internally and doesn't provide a simple way of decoupling database access from its behavior. It means we cannot unit test the following class without a SQL database.

Customer Repository
public class CustomerRepository
{
    public IList<Customer> GetCustomers()
    {
        using (var db = new AdventureWorksDataContext())
        {
            return db.Customers.ToList();
        }
    }

    public Customer GetCustomer(int id)
    {
        using (var db = new AdventureWorksDataContext())
        {
            return db.Customers.FirstOrDefault(c => c.CustomerID == id);
        }
    }
}

By using Moles, we could replace inner behavior of this class.

Note: This is White Box Testing, meaning you need to have access to internal implementation in order to know how to mock it.

Mocking with Moles

Download and install Moles.

  1. Add Mole Assemblies for the project hosting the previous class (or the code you wish to test)
  2. Add Mole Assembly for System.Data.Linq
  3. Add Mole Assembly for System.Core

Check this tutorial about Pex & Moles for more information about the previous steps.

The following code fragment unit test our GetCustomers method:

Overriding Enumeration
[TestMethod()]
[HostType("Moles")]
public void GetCustomersTest()
{
    System.Data.Linq.Moles.MTable<Customer>.AllInstances.GetEnumerator =
        tc =>
        {
            var mockCustomers = new List<Customer>()
            {
                new Customer() { FirstName = "Javier" },
                new Customer() { FirstName = "Jorge" },
                new Customer() { FirstName = "Dario" }
            };

            return mockCustomers.GetEnumerator();
        };

    CustomerRepository target = new CustomerRepository();
    var customers = target.GetCustomers();
    Assert.IsNotNull(customers);
    Assert.IsTrue(customers.Count == 3);
    Assert.AreEqual("Javier", customers[0].FirstName);
}

Check out the use of Moles to specify the behavior of enumeration for the Table<Customer> (Customers) that Linq to Sql Provider uses to execute the query in the database. In the previous code, we avoid querying data from database and return an in-memory list of customers.

When executing a lambda expression using Linq to Sql, the source Linq provider must interpret the query and then issue a command to the database.

In order to intercept the query and return mock results, we must override default behavior for the expression evaluation logic of the Linq Provider.

Overriding Expression Eval
[TestMethod()]
[HostType("Moles")]
public void GetCustomerTest()
{
    var expectedCustomer = new Customer() { FirstName = "Javier", CustomerID = 1 };

    System.Data.Linq.Moles.MTable<Customer>.AllInstances.ProviderSystemLinqIQueryableget =
        tc =>
        {
            var qp = new System.Linq.Moles.SIQueryProvider();
            qp.ExecuteExpression01(exp => expectedCustomer);
            return qp;
        };

    CustomerRepository target = new CustomerRepository();

    var actualCustomer = target.GetCustomer(expectedCustomer.CustomerID);
    Assert.IsNotNull(actualCustomer);
    Assert.AreEqual(expectedCustomer.CustomerID, actualCustomer.CustomerID);
    Assert.AreEqual(expectedCustomer.FirstName, actualCustomer.FirstName);
}

The previous mocking code returns a Mock QueryProvider that does not evaluate the expression, it simply returns the in-memory customer reference.

I encourage you that read more about Moles here.

PS: This cool framework intercepts any managed operation by creating a CLR Host for the application.

2 Comments

  • Moles is really nice if your scenario (as above) is relatively simple. People should beware however, that Moles does not support the DLR, so if you try to use it with dynamic objects you will get exceptions.

  • Thanks David, could you try the following approach and let me know how it works... http://weblogs.asp.net/mjarguello/archive/2011/04/26/using-moles-with-dlr.aspx

Comments have been disabled for this content.