How many times have you spotted software architecture that utilizes .NET Entity Framework database context as a simple Repository pattern? Let us imagine an architecture structure like this, from top to bottom:

  • Database for data persisting
  • Entity Framework DbContext as Repository pattern
  • Service layer that uses DbContext for data operations
  • Business models (not related to database) that the Service layer can return or operate
  • UI layer

The problem

How many times have you wondered how to perform unit tests in such an application service layer?
Entity Framework DbContext looks simple to mock by great tools like Moq [https://github.com/Moq/moq4/wiki/Quickstart]. Using such a tool to create a mock based on an interface is rather simple. But keep in mind that under the hood EF has mechanics for many things, like: generating ids, entity state tracking, virtual collection loading etc. Those cannot be quickly mocked, and from the unit test perspective it is worthless to spend a lot of time on mocking rather than on testing.

On one hand the perfect solution will be to refactor and introduce a pure Repository pattern layer. It would implement an interface known for the Service layer and encapsulate DBContext internally. Such a repository could be injected to the Service layer and mocked on purpose. But on the other hand it needs serious changes in the whole application architecture, which is very often not acceptable.

Based on that we know that mocking DBContext is tricky if adding a new layer requires serious changes. How to deal with such a situation? The solution could be to mock the database.

Effort-less?

Effort [https://effort.codeplex.com/] is an acronym of Entity Framework Fake ObjectContext Realization Tool. Obviously it is also able to work with DbContext objects.

How does it work?
It emulates the relational database server with a completely .NET based lightweight in-memory database. All the data operations are redirected to it, so the tests can run completely in-process.

Limitations?
It would not work with pure SQL commands, things like ExecuteStoreCommand, ADO.NET 😉 Anyway when using ORM you should also forget about these.

Test application

For testing purposes lets imagine a Shop application that has:

  • SimpleShop.DataLayer (DbContext and Entity models)
  • SimpleShop.ServiceLayer (Logic and business models)
  • SimpleShop.ServiceLayer.Tests (unit tests)

DataLayer

We have got a number of Products in Categories:

And the DbContext implementation:

ServiceLayer

The Services layer contains only one service that returns a list of Product business models:

The method here is covering the following business case “If a product starts with the letter P then apply a special discount to it”.

Setup
First we need to install Effort itself. Add Effort.EF6 package from NuGet to your unit tests project.

Save your time_effort

We need IDBConnectionFactory implementation, because we do not want to modify DBContext itself. So instead we will configure EF to use our factory when a default connection is created.

EffortProviderFactory is thread-safe-wise, and it captures the DbConnection inside. The static field handles one instance of DbConnction that is returned every time Entity Framework ask for it. The ResetDb() method is used before every test to dispose of the previous connection.

For a different scenario you can also use a method which creates a persistent database:

Effort.DbConnectionFactory.CreatePersistant(string databaseId);

It will always return the connection to the same database (based on the database parameter). But in our case it would be hard to clear the database during every test.

Note that System.Data.Common is needed here so add it from framework references:

Save your time_system data

Now we need to tell EF that a new provider should be used. In App.config (for unit test project):

The last step is little tricky, but there is a need to override the default EF provider setting per assembly. You can add a unit test class without any unit tests but with an assembly initializer like (this code will be run once per whole unit tests project):

Just start testing!

Now you can just start writing your unit tests without thinking about mocking DbContext. Once you need some data in the database simply use Entity Framework to manipulate your data. Do not worry about ids, keys, or virtual properties – everything will work in exactly the same way as with Entity Framework and an ordinary database.

Also remember to purge your Effort connection database when needed. I do it in TestInitialize method, which is run before every unit test in test class.

Let us write some examples. First, some data preparation:

Something simple at the beginning, check if products are in proper categories (testing if Service using argument to separate categories):

Then check if there is only one Pear in the Food category:

Let us test now what we really should test: business logic!

Working with Discount logic, first check if Discount applies to products that start with the letter P (the original price for Pencil is 4.0, so it is expected that the price returned from Service is 2.0, the same rule for Pen, original price is 6.0, but 3.0 should be returned):

To make sure the rule applies only to some products check if Notepad still has the regular price:

Happy testing!

.NET Developer, working with Microsoft technologies for quite a long time. Expert on the best programming practices, always eager to encourage colleagues to write top quality code. His everyday duties revolve around software architecture, object-oriented programming and project patterns. In his free time he pursues his favourite hobby – cycling.