Testing With a Fake DbContext
One of the most popular posts on my blog has been “EF CTP4 Tips & Tricks: Testing With Fake DbContext”. That post was built on a pre-release version of Entity Framework so I thought I’d provide an updated post on top of the DbContext API surface we ended up shipping.
In this post we are going to take a look at how to replace a DbContext based data access layer with an in-memory fake for unit testing.
I’m going to use an MVC controller as an example but the same approach can be used for any component that consumes a derived DbContext, including repositories.
The Problem
Say we have a very simple model for Employees and Departments and we are using DbContext to persist and query our data:
public class EmployeeContext : DbContext { public DbSet<Department> Departments { get; set; } public DbSet<Employee> Employees { get; set; } } public class Department { public int DepartmentId { get; set; } public string Name { get; set; } public ICollection<Employee> Employees { get; set; } } public class Employee { public int EmployeeId { get; set; } public int FirstName { get; set; } public int LastName { get; set; } public int Position { get; set; } public Department Department { get; set; } }
In an MVC application we could add a controller that can display all departments in alphabetical order:
(Typically we’d also implement ‘detail’, ‘create’, ‘edit’ and ‘delete’ functionality but I’m leaving them out because ‘list’ is enough to demonstrate fakes)
public class DepartmentController : Controller { private EmployeeContext db = new EmployeeContext(); public ViewResult Index() { return View(db.Departments.OrderBy(d => d.Name).ToList()); } protected override void Dispose(bool disposing) { db.Dispose(); base.Dispose(disposing); } }
The issue is that our controller now has a hard dependency on EF because it needs an EmployeeContext which derives from DbContext and exposes DbSets. We have no way to replace this with any other implementation and we are forced to run any unit tests against a real database, which means they really aren’t unit tests at all.
Adding an Interface
DbSet<T> happens to implement IDbSet<T> so we can pretty easily create an interface that our derived context implements:
public interface IEmployeeContext { IDbSet<Department> Departments { get; } IDbSet<Employee> Employees { get; } int SaveChanges(); } public class EmployeeContext : DbContext, IEmployeeContext { public IDbSet<Department> Departments { get; set; } public IDbSet<Employee> Employees { get; set; } }
Now we can update our controller to be based on this interface rather than the EF specific implementation.
(You’ll notice I’m still using the EF implementation in the default constructor, in a real world app you would probably just have the interface based constructor and use dependency injection to supply the EF implementation at runtime, but I just wanted to keep things simple for this post.)
public class DepartmentController : Controller { private IEmployeeContext db; public DepartmentController() { this.db = new EmployeeContext(); } public DepartmentController(IEmployeeContext context) { this.db = context; } public ViewResult Index() { return View(db.Departments.OrderBy(d => d.Name).ToList()); } protected override void Dispose(bool disposing) { if (db is IDisposable) { ((IDisposable)db).Dispose(); } base.Dispose(disposing); } }
Building Fakes
The first thing we need is a fake implementation of IDbSet<TEntity>, this is pretty easy to implement.
public class FakeDbSet<T> : IDbSet<T> where T : class { ObservableCollection<T> _data; IQueryable _query; public FakeDbSet() { _data = new ObservableCollection<T>(); _query = _data.AsQueryable(); } public virtual T Find(params object[] keyValues) { throw new NotImplementedException("Derive from FakeDbSet<T> and override Find"); } public T Add(T item) { _data.Add(item); return item; } public T Remove(T item) { _data.Remove(item); return item; } public T Attach(T item) { _data.Add(item); return item; } public T Detach(T item) { _data.Remove(item); return item; } public T Create() { return Activator.CreateInstance<T>(); } public TDerivedEntity Create<TDerivedEntity>() where TDerivedEntity : class, T { return Activator.CreateInstance<TDerivedEntity>(); } public ObservableCollection<T> Local { get { return _data; } } Type IQueryable.ElementType { get { return _query.ElementType; } } System.Linq.Expressions.Expression IQueryable.Expression { get { return _query.Expression; } } IQueryProvider IQueryable.Provider { get { return _query.Provider; } } System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return _data.GetEnumerator(); } IEnumerator<T> IEnumerable<T>.GetEnumerator() { return _data.GetEnumerator(); } }
There isn’t really a good way to generically implement Find, so I’ve left it as a virtual method that throws if called. If our application makes use of the Find method we can create an implementation specific to each type.
public class FakeDepartmentSet : FakeDbSet<Department> { public override Department Find(params object[] keyValues) { return this.SingleOrDefault(d => d.DepartmentId == (int)keyValues.Single()); } } public class FakeEmployeeSet : FakeDbSet<Employee> { public override Employee Find(params object[] keyValues) { return this.SingleOrDefault(e => e.EmployeeId == (int)keyValues.Single()); } }
Now we can create a fake implementation of our context:
public class FakeEmployeeContext : IEmployeeContext { public FakeEmployeeContext() { this.Departments = new FakeDepartmentSet(); this.Employees = new FakeEmployeeSet(); } public IDbSet<Department> Departments { get; private set; } public IDbSet<Employee> Employees { get; private set; } public int SaveChanges() { return 0; } }
Testing Against Fakes
Now that we have our fakes defined we can use them to write a unit test for our controller, that doesn’t use EF:
[TestMethod] public void IndexOrdersByName() { var context = new FakeEmployeeContext { Departments = { new Department { Name = "BBB"}, new Department { Name = "AAA"}, new Department { Name = "ZZZ"}, } }; var controller = new DepartmentController(context); var result = controller.Index(); Assert.IsInstanceOfType(result.ViewData.Model, typeof(IEnumerable<Department>));
var departments = (IEnumerable<Department>)result.ViewData.Model; Assert.AreEqual("AAA", departments.ElementAt(0).Name); Assert.AreEqual("BBB", departments.ElementAt(1).Name); Assert.AreEqual("ZZZ", departments.ElementAt(2).Name); }
Summary
In this post we saw how to build an interface that represents our context and how to build an in-memory fake of that context for use in our unit tests. We used an MVC controller to demonstrate this but the same approach can be used with any component that needs to interact with an EF based context, including repositories. There are a number of reasons to use in-memory fakes for unit testing but some key benefits are stable and robust tests that execute quickly and exercise a single component, making failures easy to isolate.



[...] An updated post is available here. [...]
EF CTP4 Tips & Tricks: Testing With Fake DbContext « RoMiller.com
February 14, 2012
I don’t like this technique and I consider it as a bad and dangerous practice. The reason why I don’t like it is leaky abstraction in Linq-to-entities queries. These tests give you false belief that you tested your logic inside your method under test but you actually didn’t because part of your logic is a query leaking to EF provider which is not involved in your test. In your test you have Linq-to-Objects which is superset of Linq-to-entities and only subset of queries written in L2O is translatable to L2E. You can easily get green test and failure at runtime in the code passing the test but that doesn’t make your test suite robust or trustful – it is actually very frustrating. I saw this situation so many times that I completely stopped faking context and anything exposing IQueryable – simply faking something to test completely different behavior is not useful.
At the end of the day the situation is still the same as it used to be with SQL queries defined as strings. You could fake your command to return test data but without executing the command against a real database you didn’t know if the command and thus your method works. But using integration tests for every code executing somewhere L2E query is not what we usually want to do. To solve this we can use refactoring and move all queries to separate methods with simple responsibility – execute the query. If we make those methods virtual we can easily fake them in the test (by deriving controller and overriding those methods with fake implementation. In such design we know that we can unit test our main method independently on query and only query method needs integration test. This separation will make clear that we have logic with two different scopes which needs two different test approaches.
Ladislav Mrnka
February 14, 2012
Ladislav, I want to thank you for bringing up this issue. I am evaluating how to implement UoW and Repository in a new project and would like your opinion please.
Could you please explain in more detail your solution, perhaps give an example of this ‘main’ query versus the others? I don’t quite get that.
My own initial inclination to the issue of an LTE mock is to remove the ability for the user to pass in queries to the API at all. So instead of an open ended Get(Expression(Func> filter) have a well defined GetCustomers(CustomerQueryOptions opts) for instance. It would seem like more maintenance, but tests would be more a bit more definitive. This is where I thought you were going at first…but this only solves the ‘get’ side…
Another approach, taken by the EntityFramework.Patterns project (on Nuget), is to leave EF in place, and while testing create an instance of your derived DbContext that points to a “(localdb)” instance you recreate an fill on test initialization. Since LocalDB doesn’t need to be installed or configured and it can be seeded easily, it seems like a good option. This is what I’m leaning toward, and EF.Patterns has some neat additional features like the Decorator pattern built in, too.
What do you think?
Chris
June 1, 2012
I have to agree with @Ladislav Mrnka. Mocking the EntityFramework context is not a good idea, because your tests will end up using LINQ-to-Objects, so there is no guarantee that any LINQ queries or method calls will function in the same fashion as with the “real” context. As a general rule of thumb, you should only unit test LINQ code when your unit tests will be using the same LINQ provider (LINQ-to-Objects/SQL/Entities/XML/etc) as the actual implementation.
Instead, I would recommend using a repository + unit of work pattern. The methods of the repository objects would contain the actual queries, and these methods would only be integration tested with a real database. The unit of work simply allows you to encapsulate complex operations that may involve dealing with multiple entities. You can find an example here: http://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/implementing-the-repository-and-unit-of-work-patterns-in-an-asp-net-mvc-application
Using the UoW pattern, you would create interfaces for all of your UoW and repository objects, which could then be mocked and injected in to your controllers for unit testing. You can even use libraries such as StructureMap, Castle Windsor, and Ninject to automatically build instances of your UoW and repository objects for you, and automatically inject them in to your controllers.
It should also be pointed out that you would be much better off using a mocking framework (RhinoMocks, TypeMock, Moq, Machine.Fakes, etc) rather than writing the mock implementation yourself. Not only would it be significantly less code than the example here, but it allows you to easily control expectations for input and output/return values of the mock object’s methods from test to test.
Justin Holzer
January 7, 2013
[...] (typeof(addthis_share) == "undefined"){ addthis_share = [];}Rowan Miller shows how to replace a DbContext based data access layer with an in-memory fake for unit testing in this blog post. He builds an interface that represents the context and then builds an in-memory [...]
Fake DbContext Testing
February 15, 2012
If you use an automocking container you can achieve this literally hundreds (maybe just dozens) of lines less of code.
public interface IEmployeeContext
{
IDbSet Departments { get; }
IDbSet Employees { get; }
int SaveChanges();
}
All you need to do is have your automocking container to do is handle the GetEnumerator method to handle querying. Using machine.fakes (what i use personally) this looks like
List Departments = new List { …. anything you want in your “database };
The()
.WhenToldTo(x => x.Departments.GetEnumerator())
.Return(Departments.GetEnumerator());
This will cover all of the querying you could want to do on IDbSet Departments
To handle add you would just need to do something like
The()
.WhenToldTo(x => x.Departments.Add(Param.IsNotNull))
.Return(param=>{Departments.Add(param);
return param;
});
dotnetchris
February 15, 2012
Fantastic, generics were totally eaten from code my samples
List<Department> Departments = new List<Department> { …. anything you want in your “database” };
The<IEmployeeContext>()
.WhenToldTo(x => x.Departments.GetEnumerator())
.Return(Departments.GetEnumerator());
This will cover all of the querying you could want to do on IDbSet Departments
To handle add you would just need to do something like
The<IEmployeeContext>()
.WhenToldTo(x => x.Departments.Add(Param<Department>.IsNotNull))
.Return<Department>(param=>{Departments.Add(param);
return param;
});
If you need to connect other methods like Find/Remove etc, you can easily do that too. Also with machine.fakes it’s possible for you to write this code and have it be shared very trivially see the CurrentTime example on https://github.com/BjRo/Machine.Fakes documentation
dotnetchris
February 15, 2012
Forgive me for being incredibly thick but I’ve been banging my head against the code sample for a while now – as soon as I make EmployeeContext inherit from IEmployeeContext I get the following compile error:
“EFSample.EmployeeContext’ does not implement interface member ‘EFSample.IEmployeeContext.Employees’. ‘EFSample.EmployeeContext.Employees’ cannot implement ‘EFSample.IEmployeeContext.Employees’ because it does not have the matching return type of ‘System.Data.Entity.IDbSet”
I know DbSet implements IDbSet because it’s right there in the metadata, so what am I missing?
All the code is copied and pasted and visually checked. I’ve been coding for some time now which makes me feel really stupid, I just can’t see the wood for the trees here.
Mat
February 23, 2012
Ignore me, I was being thick, maybe it’s time I got some sleep… :p
Mat
February 23, 2012
[...] Testing with a Fake DB Context – seriously awesome – we leveraged it in a recent project at work and it was a significant improvement from the Fake Repository method we had been rolling with. [...]
5/10/2012–News of the Day | Bryan Hinton on Tech and Business and …
May 10, 2012
How would you adapt this for testing methods on a controller that inherits from DbDataController?
David_C
May 14, 2012
[...] have ran into many articles about using fake DbContext, such as here, here, and here but they all seem to have some pros and cons. One group of people say that one [...]
How to write a unit test for code that uses entity framework 4.2? | PHP Developer Resource
May 24, 2012
The Find Method needs to return null – when element is not found:
http://msdn.microsoft.com/en-us/library/gg679596(v=vs.103).aspx
So, i think you need to change the code to:
public class FakeDbSetWithId : FakeDbSet where T : class, IEntity
{
public override T Find(params object[] keyValues)
{
try
{
return this.Single(d => d.Id == (int)keyValues.Single());
}
catch (ArgumentNullException ex)
{
return null;
}
}
}
I used a generic Class “FakeDbSetWithId” that derives from FakeDbSet and implements IEntity (simple Interface with Id property)
Thomas Deutsch
November 3, 2012
Just an idea.. You could pass a key selector into the constructor as Func, then your Find method could be: return _data.Single(x => keySelector(x) == keyValues.Single());
Russell Horwood
February 25, 2013
[...] do we fix the first issue, that of testability? There are actually many good examples online for this, but essentially, think about this – what is DbContext? At [...]
Why Entity Framework renders the Repository pattern obsolete? | The Cockney Coder
April 7, 2013
Thank you…just what I needed to understand!! wonderful
jj
May 2, 2013