views:

888

answers:

4

I am unit testing code written against the ADO .NET Entity Framework. I would like to populate an in-memory database with rows, and make sure that my code retrieves them properly.

I can mock the Entity Framework using Rhino Mocks, but that would not be sufficient. I would be telling the query what entities to return to me. This would neither test the where clause nor the .Include() statements. I want to be sure that my where clause matches only the rows I intend, and no others. I want to be sure that I have asked for the entities that I need, and none that I don't.

For example:

class CustomerService
{
    ObjectQuery<Customer> _customerSource;
    public CustomerService(ObjectQuery<Customer> customerSource)
    {
        _customerSource = customerSource;
    }
    public Customer GetCustomerById(int customerId)
    {
        var customers = from c in _customerSource.Include("Order")
            where c.CustomerID == customerId
            select c;
        return customers.FirstOrDefault();
    }
}

If I mock the ObjectQuery to return a known customer populated with orders, how do I know that CustomerService has the right where clause and Include? I would rather insert some customer rows and some order rows, then assert that the right customer was selected and the orders are populated.

+1  A: 

I am not familiar with Entity Framework and the ObjectQuery class but if the Include method is virtual you can mock it like this:

// Arrange
var customerSourceStub = MockRepository.GenerateStub<ObjectQuery<Customer>>();
var customers = new Customer[] 
{
    // Populate your customers as if they were coming from DB
};
customerSourceStub
    .Stub(x => x.Include("Order"))
    .Return(customers);
var sut = new CustomerService(customerSourceStub);

// Act
var actual = sut.GetCustomerById(5);

// Assert
Assert.IsNotNull(actual);
Assert.AreEqual(5, actual.Id);
Darin Dimitrov
There are two features of the GetCustomerById method: the where clause, and the include. If I mock the customer source to return a known customer, I'm testing neither of them.
Michael L Perry
If you mock the Include method you are not returning a known customer but a list of known customers so you can test the where clause to see if it finds the customer by it's id. As far as the Include method is concerned, you also verify that you call it with the correct argument: Order
Darin Dimitrov
A: 

Yes, there is at least one such provider - SQLite. I have used it a bit and it works. Also you can try SQL Server Compact. It's an embeded database and has EF providers too.
Edit:
SQLite has support for in-memory databases (link1). All you need is to specify a connection string like: "Data Source=:memory:;Version=3;New=True;". If you need in an example you may look at SharpArchitecture.

zihotki
I could use an embedded (in-process) database, but I'd prefer to go completely in-memory. I'd like to define my tables and populate some rows completely in code, and never write anything to disk. Then I could have the unit test verify that my CustomerService queries that data correctly.
Michael L Perry
SQLite supports in-memory databases, see edited answer.
zihotki
I would prefer an actual db run within memory because the most important thing to test is db relationships and constraints and you have little support for that in code. What bothers me is that this is application logic and should be represented in you model and not in the database.
TT
What would be perfect is some kind of .net collections that could mimic the database tables, their relationships and constraints which would allow to to create a database entirely in memory and would allow you to create ddl to export to your real database when you are done testing
TT
Use NHibernate for ORM. Structure of the database will be presented with your entities. And this structure easily can be exported to many various databases (especially when you use DDD). And it can be easily tested using in-memory SQLite db. See SharpArchitecture for a sample.
zihotki
+3  A: 

A better approach here might be to use the Repository pattern to encapsulate your EF code. When testing your services you can use mocks or fakes. When testing your repositories you will want to hit the real DB to ensure that you are getting the results you expect.

Andrew Peters
If I just mock the Repository to return a given Customer, this doesn't test the Specification. I want to include the Specification in the unit test, and not wait until I'm using a real DB.
Michael L Perry
Lol.. And how LINQ2Entities queries can be tested with Repository pattern? There are no way to do this because these queries will generate sql queries and we need to test them in the database too.
zihotki
I'm accepting this answer because it is the closest thing to what I actually did. I created interfaces in the shape of the Repository pattern, then implemented both an EF adapter and an in-memory test harness. It doesn't test the DB, but it does test my own Specifications.
Michael L Perry
A: 

You could try SQL Server Compact but it has some quite wild limitations:

  • SQL Server Compact does not support SKIP expressions in paging queries when it is used with the Entity Framework
  • SQL Server Compact does not support entities with server-generated keys or values when it is used with the Entity Framework
  • No outer joins, collate, modulo on floats, aggregates
Chris S