Testing the queries in your data access layer

Posted on Updated on

When it comes to writing automated tests I have, in the past, tended to ignore the data access layer. Do you really need to test your queries? As long as the code was loosely coupled and I could test everything else, I was happy. After talking at work I was convinced that, in some cases, it might be worth testing your queries themselves in order to check that they’re returning the data that they should be.

This provided a dilemma, because I will always try to avoid writing integration/database tests if I can help it, but how do you test queries without a database? A possible answer is as follows, taken from my post on StackOverflow:

 

After some deliberation, my colleague and I came up with a way to separate the query from the persistence layer. I threw together a quick example below:

public class Invoice
{
    public int Id {get; set;}
    public DateTime DueOn {get; set;}
    public DateTime MadeOn {get; set;}
    public decimal Total {get; set;}
    public Customer Customer {get;set;}
}

public class Customer
{
    public int Id {get; set;}
    public string Name {get; set;}
}

public class OverdueInvoice
{
    public int CustomerId {get; set;}
    public int InvoiceId {get; set;}
    public string CustomerName {get; set;}
    public decimal Total {get; set;}
}

public class InvoiceQueries
{
    private readonly IReadRepository<Invoice> _invoices;

    public InvoiceQueries(IReadRepository<Invoice> invoices)
    {
        _invoices = invoices;
    }

    public IEnumerable<OverdueInvoice> GetAllOverdueInvoices(TimeSpan timeOverdue)
    {
        return _invoices
            .FindAll(invoice => invoice.DueOn - timeOverdue > DateTime.Now)
            .Select(Map);
    }

    private OverdueInvoice Map(Invoice invoice)
    {
        return new OverdueInvoice
        {
            CustomerId = invoice.Customer.Id,
            InvoiceId = invoice.Id,
            CustomerName = invoice.Customer.Name,
            Total = invoice.Total,
        };
    }
}

public class InMemoryInvoicesRepository : IReadRepository<Invoice>, IWriteRepository<Invoice>
{
    private List<Invoice> _backingStore;

    public InMemoryInvoicesRepository() : this(new List<Invoice>())
    {}

    public InMemoryInvoicesRepository(List<Invoice> backingStore)
    {
        _backingStore = backingStore;
    }

    public IEnumerable<Invoice> FindAll(Predicate<Invoice> predicate)
    {
        return _backingStore.FindAll(predicate);
    }

    public void Add(Invoice item)
    {
        _backingStore.Add(item);
    }
}

public interface IReadRepository<T>
{
    IEnumerable<T> FindAll(Predicate<T> predicate);
}

public interface IWriteRepository<T>
{
    void Add(T item);
}

Separating the data access into a ‘query’ object and a ‘repository’ object allows you to replace the repository at test time with an in-memory collection. This way, you can fill a List with whatever objects you want and then test your query layer by running it against that list. The repository is a really dumb object that takes your query and just passes it through to your ORM (to actually do this Func might have to be replaced by Expression>).

 

The StackOverflow question can be found here: http://stackoverflow.com/questions/22013850/is-it-worth-testing-data-access-queries-themselves/22048531#22048531

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s