40

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.

Michael L Perry
  • 7,327
  • 3
  • 35
  • 34
  • 1
    Like you ended up doing, I've used interfaces to follow the Repository Pattern and the Unit Of Work pattern. Then, i have two namespaces -> EF and Fake. With my Fake repository, i just used IList to store my stuff and leverage Linq to Objects to extract the data. Works great :) – Pure.Krome Dec 11 '09 at 10:33
  • 4
    EntityFramework 7 has InMemoery provider now. Still beta as of commenting but if you subscribe to the nightly nuget you can get it. – Piotr Kula Jan 22 '15 at 14:42

8 Answers8

16

An InMemory provider is included in EF7 (pre-release).

You can use either the NuGet package, or read about it in the EF repo on GitHub (view source).

Denis Biondic
  • 7,943
  • 5
  • 48
  • 79
Shimmy Weitzhandler
  • 101,809
  • 122
  • 424
  • 632
  • 4
    While that's true, EF7 is still very much pre-release and Microsoft has stated that EF7 is NOT simply the next version from EF6; which is why they have renamed it EF Core 1.0 – Tim Long May 22 '16 at 03:32
  • Our team decided not to touch EF7 until complex-types and TPT is implemented. EF7 is too raw. – Shimmy Weitzhandler Aug 09 '17 at 09:50
13

The article http://www.codeproject.com/Articles/460175/Two-strategies-for-testing-Entity-Framework-Effort  describes Effort  -Entity Framework provider that runs in memory.

You can still use your DbContext or ObjectContext classes within unit tests, without having to have an actual database.

John Cummings
  • 1,949
  • 3
  • 22
  • 38
Michael Freidgeim
  • 26,542
  • 16
  • 152
  • 170
9

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
  • 11,135
  • 4
  • 37
  • 34
  • 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 Feb 23 '09 at 02:06
  • 1
    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 Feb 23 '09 at 08:26
  • 1
    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 Mar 02 '09 at 15:46
  • Yes use Moq with InMemoryDbSet. This does not work for outer join but is good for inner join LINQ queries. – Kremena Lalova Jul 15 '14 at 13:11
  • 3
    A Repository over a DbContext is a leaky abstraction and does more harm than anything. – SuperJMN Feb 05 '18 at 16:54
7

There is not currently a in memory provider for EF, but if you take a look at Highway.Data it has a base abstraction interface and an InMemoryDataContext.

Testing Data Access and EF with Highway.Data

Devlin Liles
  • 94
  • 1
  • 2
  • 8
    This is no longer the correct answer. EF7 now supports InMemory... well, when its released in the not so distant future. – Piotr Kula Jan 22 '15 at 14:43
  • 3
    It is in Beta as of this writing. Look for EntityFramework.InMemory on NuGet. – HiredMind Feb 16 '15 at 18:15
  • While EF7 will include an InMemory provider... It is my understanding that the InMemory provider is highly abstracted in that it mimics the common features of all providers. You'll need to use something like the EntityFramework.SqlLite provider for unit tests that require validation of certain provider-specific concepts. For example, I wasn't able to verify unique constraints or required field constraints using the InMemory provider. You also can't validate relational constraints with it. More details here: https://github.com/aspnet/EntityFramework/issues/2166 – Paul Jul 01 '15 at 23:20
  • 1
    FWIW, we go against a live dev database (since we actively use it for sandbox anyway) and just wrap test class in a transaction scope. https://msdn.microsoft.com/en-us/library/aa833153(v=vs.100).aspx – kamranicus Sep 22 '15 at 13:46
6

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
  • 5,201
  • 22
  • 26
  • 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 Feb 23 '09 at 02:37
  • 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. – terjetyl Feb 23 '09 at 08:44
  • 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 – terjetyl Feb 23 '09 at 08:51
  • 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 Feb 23 '09 at 16:27
  • note that if the models contain Time data types, that doesn't currently appear to be supported by SQLite in Entity Framework: http://stackoverflow.com/questions/32097637/sql-lite-throwing-system-notsupportedexception-for-time-data-type-in-sql (I tried with SQLite nuget package v1.0.105.1). – danio May 16 '17 at 09:43
2

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
  • 1,023,142
  • 271
  • 3,287
  • 2,928
  • 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 Feb 23 '09 at 02:11
  • 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 Feb 23 '09 at 10:09
1

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
  • 64,770
  • 52
  • 221
  • 239
0

In EF Core there are two main options for doing this:

  1. SQLite in-memory mode allows you to write efficient tests against a provider that behaves like a relational database.
  2. The InMemory provider is a lightweight provider that has minimal dependencies, but does not always behave like a relational database

I am using SQLite and it supports all queries, that I need to do with Azure SQL production database.

Michael Freidgeim
  • 26,542
  • 16
  • 152
  • 170