Testing with a mocking framework

In this article

Note

EF6 Onwards Only - The features, APIs, etc. discussed in this page were introduced in Entity Framework 6. If you are using an earlier version, some or all of the information does not apply.

When writing tests for your application it is often desirable to avoid hitting the database. Entity Framework allows you to achieve this by creating a context – with behavior defined by your tests – that makes use of in-memory data.

Options for creating test doubles

There are two different approaches that can be used to create an in-memory version of your context.

Create your own test doubles – This approach involves writing your own in-memory implementation of your context and DbSets. This gives you a lot of control over how the classes behave but can involve writing and owning a reasonable amount of code.

Use a mocking framework to create test doubles – Using a mocking framework (such as Moq) you can have the in-memory implementations of your context and sets created dynamically at runtime for you.

To demonstrate using EF with a mocking framework we are going to use Moq. The easiest way to get Moq is to install the Moq package from NuGet.

Testing with pre-EF6 versions

The scenario shown in this article is dependent on some changes we made to DbSet in EF6. For testing with EF5 and earlier version see Testing with a Fake Context.

Limitations of EF in-memory test doubles

In-memory test doubles can be a good way to provide unit test level coverage of bits of your application that use EF. However, when doing this you are using LINQ to Objects to execute queries against in-memory data. This can result in different behavior than using EF’s LINQ provider (LINQ to Entities) to translate queries into SQL that is run against your database.

One example of such a difference is loading related data. If you create a series of Blogs that each have related Posts, then when using in-memory data the related Posts will always be loaded for each Blog. However, when running against a database the data will only be loaded if you use the Include method.

For this reason, it is recommended to always include some level of end-to-end testing (in addition to your unit tests) to ensure your application works correctly against a database.

Following along with this article

This article gives complete code listings that you can copy into Visual Studio to follow along if you wish. It's easiest to create a Unit Test Project and you will need to target .NET Framework 4.5 to complete the sections that use async.

The EF model

The service we're going to test makes use of an EF model made up of the BloggingContext and the Blog and Post classes. This code may have been generated by the EF Designer or be a Code First model.

Virtual DbSet properties with EF Designer

Note that the DbSet properties on the context are marked as virtual. This will allow the mocking framework to derive from our context and overriding these properties with a mocked implementation.

If you are using Code First then you can edit your classes directly. If you are using the EF Designer then you’ll need to edit the T4 template that generates your context. Open up the <model_name>.Context.tt file that is nested under you edmx file, find the following fragment of code and add in the virtual keyword as shown.

Service to be tested

To demonstrate testing with in-memory test doubles we are going to be writing a couple of tests for a BlogService. The service is capable of creating new blogs (AddBlog) and returning all Blogs ordered by name (GetAllBlogs). In addition to GetAllBlogs, we’ve also provided a method that will asynchronously get all blogs ordered by name (GetAllBlogsAsync).

Testing non-query scenarios

That’s all we need to do to start testing non-query methods. The following test uses Moq to create a context. It then creates a DbSet<Blog> and wires it up to be returned from the context’s Blogs property. Next, the context is used to create a new BlogService which is then used to create a new blog – using the AddBlog method. Finally, the test verifies that the service added a new Blog and called SaveChanges on the context.

Testing query scenarios

In order to be able to execute queries against our DbSet test double we need to setup an implementation of IQueryable. The first step is to create some in-memory data – we’re using a List<Blog>. Next, we create a context and DBSet<Blog> then wire up the IQueryable implementation for the DbSet – they’re just delegating to the LINQ to Objects provider that works with List<T>.

We can then create a BlogService based on our test doubles and ensure that the data we get back from GetAllBlogs is ordered by name.

Testing with async queries

Entity Framework 6 introduced a set of extension methods that can be used to asynchronously execute a query. Examples of these methods include ToListAsync, FirstAsync, ForEachAsync, etc.

Because Entity Framework queries make use of LINQ, the extension methods are defined on IQueryable and IEnumerable. However, because they are only designed to be used with Entity Framework you may receive the following error if you try to use them on a LINQ query that isn’t an Entity Framework query:

The source IQueryable doesn't implement IDbAsyncEnumerable{0}. Only sources that implement IDbAsyncEnumerable can be used for Entity Framework asynchronous operations. For more details see http://go.microsoft.com/fwlink/?LinkId=287068.

Whilst the async methods are only supported when running against an EF query, you may want to use them in your unit test when running against an in-memory test double of a DbSet.

In order to use the async methods we need to create an in-memory DbAsyncQueryProvider to process the async query. Whilst it would be possible to setup a query provider using Moq, it is much easier to create a test double implementation in code. The code for this implementation is as follows: