Testing With a Fake DbContext

Posted on February 14, 2012. Filed under: Entity Framework, Testing, Visual Studio | Tags: , , , , , , , |

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.

About these ads

Make a Comment

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

30 Responses to “Testing With a Fake DbContext”

RSS Feed for RoMiller.com Comments RSS Feed

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, 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?

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.

[…] (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 […]

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;
});

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

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.

Ignore me, I was being thick, maybe it’s time I got some sleep… :p

I also encountered this issue…it happens because I didn’t change the DbSet to IDbSet on the “EmployeeContext” class:
public DbSet Departments { get; set; }
should be changed to:
public IDbSet Departments { get; set; }

[…] 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. […]

How would you adapt this for testing methods on a controller that inherits from DbDataController?

[…] 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 […]

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)

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());

[…] 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 […]

Thank you…just what I needed to understand!! wonderful

I’ve extended some of the basic ideas along with code generation for an automatically generated dbcontext.

http://mockingcompetence.wordpress.com/2013/05/20/fakingefdatacontext/

Great stuff. For EF6, the ObservableCollection is now DbLocalView (System.Data.Entity.Infrastructure), and there’s a FindAsync that you have to override, returning Task of T instead of just T.

Oh yeah – I philosophically disagree that this is a bad approach. “Unit” tests shouldn’t have a dependency on a database; sorta defeats the purpose of testing the unit (especially for those of us who back it with Postgres).

On to testing!

In EF6 RC1 they’ve reverted DbLocalView back to ObservableCollection

We reverted IDbSet back to it’s original state because we made a bunch of improvements to DbSet itself to allow you to test without needing the interface in EF6.

Here is some info on doing this:
– with a mocking framework http://msdn.com/data/dn314429
– creating your own test doubles (as shown in this post) http://msdn.com/data/dn314431

Great Article.
How would you achieve this with Microsoft Fakes?

Just found this updated posting. You say you can removed a hard dependency on EF5 by using IDbSet. IDbSet appears to be defined by EF, though. How can I use IDbSet to remove my dependency on EF itself?

Thanks

[…] example and how make a fake DBContex For test my test using just this work fine […]

For anyone trying to follow this approach while keeping your Repository and UnitOfWork fully generic while keeping with EF5 (EF6 works due to the new default DbSet() constructor), I would suggest instead checking out:

http://gaui.is/how-to-mock-the-datacontext-entity-framework/

It’s about mocking your Repository and UnitOfWork instead of DbSet.

Hi ,
I think this would work for Code first approach,May I know how can I do this for database first approach,
Autogenerated class inherited from ObjectContext instead from DbCOntext.

Personally I don’t like this approach, you should look into Effort, it’s a tool for making in memory representation of your DB. Here’s the link https://effort.codeplex.com/wikipage?title=Create%20a%20fake%20DbContext%20instance.

I agree that an in memory database can provide something closer to the behavior you will get when you target a real database. Actually, in EF7 we will have an in memory provider baked into EF. You still need to do some level of functional testing against the real database though, as things like string comparison etc. can vary between providers.

You can now generate interface for your DbContext via Entity Framework Interface Generator (https://entityinterfacegenerator.codeplex.com/)

Then, use the fake DbContext technique above to fully test your application without hitting an actual database.

One nice thing in EF6 is that you can now just Mock/Fake the context without having to create an interface on it. See http://msdn.microsoft.com/en-us/data/dn314429 for an example.


Where's The Comment Form?

    About

    Rowan works as a Program Manager for the ADO.NET Entity Framework team at Microsoft. He speaks at technical conferences and blogs at romiller.com. Rowan lives in Seattle, Washington with his wife Athalie. Prior to moving to the US he resided in the small state of Tasmania in Australia. Outside of technology Rowan's passions include snowboarding, mountain biking, horse riding, rock climbing and pretty much anything else that involves being active. The primary focus of his life, however, is to follow Jesus.

    RSS

    Subscribe Via RSS

    • Subscribe with Bloglines
    • Add your feed to Newsburst from CNET News.com
    • Subscribe in Google Reader
    • Add to My Yahoo!
    • Subscribe in NewsGator Online
    • The latest comments to all posts in RSS

    Meta

Liked it here?
Why not try sites on the blogroll...

Follow

Get every new post delivered to your Inbox.

Join 171 other followers

%d bloggers like this: