Testing Entity Framework 4

Entity Framework has previously been a real pain in the backside to unit test and this slowed my own development of unit testing skills. It’s so much quicker to “just get it done” when deadlines loom. The new Entity Framework 4 promised POCO (Plain-old-CLR-objects) support which allows us to separate our concerns from the underlying database, just what you need to “mock out” the database.

I’ve spent hours trawling through Microsoft’s own recommendations and others’, but I just couldn’t find a model that was actually usable or reasonable. That said, I have drawn heavily from Microsoft’s own solutions:

My complaints for the above solutions were two fold. Firstly, they (and indeed the practicalities of implementing an abstracted Repository pattern) seem to push you towards strongly typing your Repository to a particular class within your domain. So, you would have a CustomerRepository, an InvoiceRepository, etc. These would be either strongly typed or implemented through Generics, such as Repository<TEntity>. Patterns often don’t map well to “real life”, and I’m a great fan of real life. In real life, objects interact with other objects and restricting Repositories by Types isn’t going to help this interaction. Secondly, the UnitOfWork pattern seemed superfluous and it just ended up with added levels of abstraction that I don’t feel were worth the lines of code.

This post will detail how I have implemented a common pattern that is easily unit testable/mockable. It is not a panacea for all, though. Deadlines and commercial constraints enforce a degree of the Duct-tape programmer in my work and I have had to make compromises. While I would have liked to mock the concrete data objects themselves and handle through interfaces (eg. ICustomer), this was not possible due to casting through IObjectSet<T>, so I’ve settled on using the generated concrete data objects instead. Therefore, the references to the Entity Framework DLLs (and therefore database reliant code) is required – though not used for database access.

Here’s how I did it, do let me know if you have any comments on my implementation …

I’ve prepared a diagram to try and illustrate the method:

Schematic

The Concrete Entity Framework is a standard configuration, and is abstracted away by the IRepositoryObjectContext interface. This allows the development of a side-by-side Testing Context, using Entity Framework-generated POCO classes, but using the same concrete generated classes as the standard Entity Framework. Client applications (including Test harnesses, etc.) access the appropriate context via the Repository, which is injected with the appropriate instance of IRepositoryObjectContext. The Business/ORM objects are implemented as interfaces and presented to the client application as interfaces, not as the original classes. This does pose problems in hydration of objects through WCF, etc. but Entity Framework doesn’t deal well with that anyway, so DTOs are still the order of the day.

First, I created a new Solution. This would represent the end application in reality, but just to test this, it’s just for the purpose of illustrating/testing the methodology. The Solution contains the “business” layer (“PatternsAndPractises.TestableEntityFramework”), the client application (“PatternsAndPractises.TestableEntityFramework4.Web.Client” – in this case an ASP.NET Web Application) and the Test project (“PatternsAndPractises.TestableEntityFramework4.Tests” – using the Test Project template).

Solution screenshot

The database is stored within the App_Data folder of the web application, which is fairly typical. I’ve created a single Customers table in it.

Database in Solution screenshot

The Customers table has a primary key of integer set to identity increment and a string (VARCHAR/NVARCHAR) field CustomerName.

The next step is to integrate Entity Framework into the project. I created a Data folder (and therefore namespace for new files) that will contain the persistence-layer objects and contexts. Inside here, I created the Entity Model by using “Add New Item” and selecting “ADO.NET Entity Data Model”, and following the wizard to extract the schema from the database, select the database created earlier and add the tables. I’ve now got a [simplistic] model. Opening the generated “code-behind” within the Model.Designer.cs file reveals the class used to manage the entities, TestDatabaseEntities (which will be derived from the settings you chose while you were configuring the wizard).

Data Model generated context class

This generated class is important as it provides the means by which we can extend the basic generated implementation to abstract away the database-code. To achieve this, we create a new class, make it partial and apply the same class name.

In addition, we make it implement the interface IRepositoryObjectContext. The interface doesn’t exist yet, but this will give us the abstraction layer we need to present different entity contexts to our repository later.

TestDatabaseEntities partial class screenshot

To create the interface, IRepositoryObjectContext, we’ll add a new interface at the project level (ie. above the Data folder/namespace) and define the implementation:

IRepositoryObjectContext screenshot

This interface needs to expose the bare minimum required for the Repository to be able to interact with the data-store (physical or otherwise). The CustomersSet is used to abstract away the implementation of the set used by the Entity Data Context class (but not the generated concrete data class). This provides all the services a Repository would expect from an Entity Framework API. The SaveChanges method provides persistence of changes to objects. This interface also implements IDisposable, which allows the use of the using() {} block for automatic resource clean-up even though we’re abstracting away the Entity Framework API. We don’t need to implement the IDisposable interface, the generated code from Entity Framework does this for us.

This abstracts-away the implementation detail of Entity Framework, but it still relies on the concrete generated data classes (for example, Customer) and some awareness that the application is using Entity Framework. This is where the Repository class comes in.

using System;
using System.Collections.Generic;
using System.Linq; 
using System.Text;
using System.Data.Objects;
using PatternsAndPractises.TestableEntityFramework4.Data;

namespace PatternsAndPractises.TestableEntityFramework4 
{
    public class Repository : IDisposable
    {
        protected IRepositoryObjectContext RepositoryObjectContext 
		{ get; private set; }

	#region ~ Constructors ~

	public Repository(
		IRepositoryObjectContext repositoryObjectContext)
        {
            RepositoryObjectContext = repositoryObjectContext;
        }

	#endregion

	public ICustomer CreateCustomer()
        {
            ICustomer newCustomer = new Customer();
            newCustomer.CustomerName = "New Customer";
            return newCustomer;
        }

	public void AddCustomer(ICustomer customer)
        {
            RepositoryObjectContext
		.CustomersSet.AddObject((Customer)customer); 
        }

	public void SaveChanges()
        {
            RepositoryObjectContext.SaveChanges();
        }
	
	public IQueryable<ICustomer> Customers
        {
            get
            {
                return 
			(IQueryable<Customer>)
			RepositoryObjectContext.CustomersSet;
            }
        }

	#region ~ from IDisposable ~

	public void Dispose()
        {
            RepositoryObjectContext.Dispose();
        }

	#endregion
    }
}

This class is the point at which the abstraction of the Entity Framework is implemented, by virtue of injecting the IRepositoryObjectContext implementing class into the constructor. We’ve only got one of these at the moment, being the actual Entity Framework generated class, coupled with our partial extension and implementation of IRepositoryObjectContext.

The Repository uses the IRepositoryObjectContext to implement the standard CRUD functionality of adding, saving and querying data. The CreateCustomer() method simply creates an object, and does not persist it. I like the idea of “default objects” to be creatable then sent to the user interface which can then provide additional logic such as undo-steps, etc. The class provides the Customers of the underlying Entity Framework via the CustomersSet property, but cast to an IQueryable<ICustomer> set. This removes the additional functionality provided by the Entity Framework 4 IObjectSet<T> class and casts it to the ICustomer interface, effectively making the set read-only. The ICustomer interface will abstract away the concrete data class, Customer. Finally, we implement IDisposable, which propagates the disposal upto the repository and finally, the Entity Data Context.

To complete the circle, the ICustomer class means that when the client application works with Customers, it always works with ICustomer and therefore doesn’t need to involve itself with the concrete generated data classes. The ICustomer interface defines the properties and access permissions for individual fields, you wouldn’t want the primary key to be set, for example:

ICustomer screenshot

In order that the generated Customer concrete class implements the ICustomer interface, we create a partial class, Customer:

12-06-2010 13-08-03

This essentially completes the business object layer, which is immediately usable by a client application. The project would look like this:

Completed business-layer project screenshot

Notice the RepositoryFactory class. This simple creates an instance of the Repository class, injecting the appropriate data context as an implementation of the IRepositoryObjectContext interface:

RepositoryFactory screenshot

Adding Testability

The testing portions of the solution will be added to the PatternsAndPractises.TestableEntityFramework4.Tests project, which will attempt to mirror  the business layer in all respects except for the persistence of data.

In the same way as the business layer, we shall separate our classes into persistence and logical layers by adding the Data folder/namespace.

Within this folder we need to mimic the Entity Framework API, which is made possible by the POCO Template for Entity Framework. Downloading this and installing into Visual Studio allows the creation of T4 templates according to the schema already defined in the Entity Model we created earlier, and it’s easily done.

Going back to the Entity Model defined earlier, right-click on the design surface (not on an object) and select “Add Code Generation Item”.

12-06-2010 12-48-38

Once prompted, select ”ADO.NET POCO Entity Generator” and name the item, for example “MockableModel”.

12-06-2010 12-49-42

The T4 templates will be created, which in turn auto-generates the concrete classes.

12-06-2010 12-53-58

You won’t need the Model templates or classes, so you can remove these from the project (highlighted in red).

Before going any further, the action of generating these POCO classes disables the default code generation of Entity Framework, which needs to be re-enabled. (Opening the generated .designer.cs file illustrates this by a comment.) This may be re-enabled by opening the Model, clicking on the design surface and using the Properties pane to set the Code Generation Strategy back to “Default”. Saving the model will regenerate the underlying classes.

12-06-2010 13-05-25

Clearly, the mock templates/code are related to the mocking/testing of the solution so would be more appropriately placed within the PatternsAndPractises.TestableEntityFramework4.Tests project so can be moved to live within the Data folder within the test project.

This will create a problem in that the T4 template needs to locate the source schema provided by the Entity Model, which is now unavailable. This can be corrected by opening the MockableModel.Context.tt file (or whatever you have called yours) and locating the line where the inputFile is set and changing it to the relative location of the .edmx file.

12-06-2010 13-00-06

(If your editor doesn’t display with the helpful colouring, download the Tangible T4 Editor – it makes it a lot easier)

Saving the file will cause the MockableModel.Context.cs file to be re-generated with the concrete classes defining ObjectSet accessors for each class/table. These will be referencing the concrete generated classes defined in the data-layer – a weakness in this model.

A further change that needs to be made to the template is to weaken the ObjectSet references to the IObjectSet<T> type to allow abstraction. In order to add the IObjectSet<T> type, the System.Data.EntityClient namespace needs to be added. The changes are highlighted in the screenshot below, in green and indicated by arrows as the template colouring reduces identification.

Changes to MockableModel.Context.tt template screenshot

In the same way that we extended the functionality of the original Model context, we create a similar partial class for the MockableModel class (which actually refers to the local TestDatabaseEntities class). Notice that this is also implementing the IRepositoryObjectContext interface defined earlier. This is the testable/mockable object context. We have to create this within a separate folder, to prevent the generated file from being overwritten. I created a “Partial” folder within Data, making sure that “Partial” did not become part of the namespace – which would prevent the partial compilation from working.

12-06-2010 13-16-57

While this essentially completes our obligations in terms of implementing the IRepositoryObjectContext interface, it doesn’t yet work. The CustomersSet is created on demand by the generated code, as shown in the snippet below, from MockabelModel.Context.cs:

12-06-2010 13-19-34

However, the ObjectSet doesn’t actually retain any objects added to it, so we need to create an in-memory persistence layer that will essentially perform the same as the database persistence layer of the original Entity Framework. The article Testability and Entity Framework 4 defines the InMemoryObjectSet class:

using System.Linq;
using System.Collections;
using System.Collections.Generic;
using System.Linq.Expressions;
using System;
using System.Data.Objects;

public class InMemoryObjectSet : IObjectSet where T : class
{
	private readonly HashSet _set;
    private readonly IQueryable _queryableSet;

	public string Name { get; set; }

	#region ~ Constructors ~

	public InMemoryObjectSet()
		: this(Enumerable.Empty())
	{
	}

	public InMemoryObjectSet(IEnumerable entities)
	{
		_set = new HashSet();
		foreach (var entity in entities)
		{
			_set.Add(entity);
		}
		_queryableSet = _set.AsQueryable();
	}

	public InMemoryObjectSet(string name)
		: this()
	{
		Name = name;
	}

	public InMemoryObjectSet(string name, IEnumerable entities)
		: this(entities)
	{
		Name = name;
	}

	#endregion


	#region ~ from IObjectSet ~

	public void AddObject(T entity)
	{
		_set.Add(entity);
	}
	public void Attach(T entity)
	{
		_set.Add(entity);
	}
	public void DeleteObject(T entity)
	{
		_set.Remove(entity);
	}
	public void Detach(T entity)
	{
		_set.Remove(entity);
	}
	public Type ElementType
	{
		get { return _queryableSet.ElementType; }
	}
	public Expression Expression
	{
		get { return _queryableSet.Expression; }
	}
	public IQueryProvider Provider
	{
		get { return _queryableSet.Provider; }
	}
	public IEnumerator GetEnumerator()
	{
		return _set.GetEnumerator();
	}
	IEnumerator IEnumerable.GetEnumerator()
	{
		return GetEnumerator();
	}

	#endregion

}

This class uses an instance of a HashSet<T> to persist data, which produces contextless and fast storage without dependency on state or implementation of a database.

In order to implement the addition of items to the various sets, in this case Customers, I overrode the CreateObjectSet<T> method by using “new” within the TestDatabaseEntities class, which now looks like:

12-06-2010 13-25-57

This skips the original behaviour and instead creates an InMemoryObjectSet of T to ensure a container is actually created for storage of objects.

As the actual Entity Framework code is called in the mocking of the Entity Framework API, there is a dependency on the connection string – but only for configuration purposes, no connection is made. Therefore, we need to copy the App.config file from the business layer project “PatternsAndPractises.TestableEntityFramework4” to the Test project “PatternsAndPractises.TestableEnityFramework4.Tests”.

The project now looks like:

12-06-2010 13-30-47

Now would be a good point at which to confirm everything compiles.

We’re now ready to write our tests. As with the data layer, we need to be able to invoke the Repository class and inject our Entity Context, which implements IRepositoryObjectContext. I find creating a base class (“TestBase”) for tests works just as well as the Factory method used previously:

12-06-2010 13-33-19

The CreateRepository method creates the Repository, injecting the [local] instance of TestDatabaseEntities, or IRepositoryObjectContext.

Finally, to write the tests, we’ll create a customer and save it, then check the persistence store to ensure it has been stored. Create a new Unit Test class and add the following tests:

		[TestMethod]
		public void CreateAndAddCustomer()
		{
			string expectedCustomerName = 
				string.Format("New Customer ({0})", Guid.NewGuid());
			using (Repository repository = CreateRepository())
			{
				ICustomer customer = repository.CreateCustomer();
				customer.CustomerName = expectedCustomerName;

				repository.AddCustomer(customer);
				repository.SaveChanges();

				ICustomer retainedCustomer = repository.
					Customers.
					Where(q => q.CustomerName == expectedCustomerName).
					FirstOrDefault();
				Assert.IsNotNull(retainedCustomer);
			}	
		}

This test will create a customer (but not store it), add it to the persistence layer (in this case, an in-memory HashSet), save the changes and use the IQueryable<T> interface to verify the operation worked.

The full Solution (exlcuding the Web UI) would look like:

12-06-2010 13-39-27

Like I said, it’s not perfect, nor is it 100% isolated, but I think it strikes a healthy compromise between testability and the ability to concentrate on the job in hand, rather than worrying about minutia of patterns and practises. If you have any comments, do post them.

I’ve added a sample project to download to provide a usable sample. Download the Visual Studio 2010 Solution as a ZIP file.

Comments

# re: Testing Entity Framework 4

Tuesday, June 15, 2010 4:17 PM by Phil

Any chance of a download of the solution?

# re: Testing Entity Framework 4

Tuesday, June 15, 2010 4:32 PM by Nathan Pledger

Yes, of course. I was meaning to get round to doing that. Need to make a few updates to the post, too. Will get on to that tonight (BST).

# Unit Testing Entity Framework 4.0

Sunday, September 12, 2010 6:18 AM by Andy's blog

Unit Testing Entity Framework 4.0

# re: Testing Entity Framework 4

Wednesday, February 02, 2011 9:50 AM by SD

Can you reput the zip file of the solution plz ?

# re: Testing Entity Framework 4

Thursday, February 10, 2011 8:51 PM by Nathan Pledger

Sorry about the delay, had some issues to sort out. The ZIP file of a VS2010 project is here:

programx.co.uk/.../TestableMockableEntityFramework4.zip

Leave a Comment

(required) 
(required) 
(optional)
(required) 
Please add 7 and 3 and type the answer here: