Mocking your Entity Framework data context and testing it in .NET MVC

I explained in my previous post Do we need the repository pattern? why you might want to mock your Entity Framework context rather than using the repository pattern. In this post I’ll show you how to do that and how to test your .NET MVC controllers with a fake data context.

The way you do this varies slightly depending on whether you're using code first or database first. I’ll cover both in this post.

Using Code First in Entity Framework 4

My implementation of code first is based heavily on the blog post by Rowan Miller.

A mockable data context (EF Code First)

When you create your code first DBContext it is very easy to make it include an interface that can be mocked. Here is a simple example:

public interface IContext
{
    IDbSet<Foo> Foos { get; set; }
    IDbSet<Bar> Bars { get; set; }

    int SaveChanges();
}

public class EFContext : DbContext, IContext
{
    public IDbSet<Foo> Foos { get; set; }
    public IDbSet<Bar> Bars { get; set; }
}

Using you mockable context in a controller (EF Code First)

This is also very easy. I’d recommend using a proper dependency injection framework like AutoFac, but in this example I’m going to use to use poor mans DI to keep it simple.

public class HomeController
{
    private IContext _data { get; set; }

    public HomeController(IContext dataContext = null)
    {
        _data = dataContext ?? new EFContext();
    }

    public ViewResult Index()
    {
        var items = _data.Foos
                .Include(f => f.FooBit)
                .ToList();

        return View(items);   
    }
}

The nice thing here is we’ve been able to specify that we want to bring down information from the related entity FooBit. This means our view can show information from both the list of Foo objects and all the separate FooBits without creating a N+1 problem.

Unit testing our controller (EF Code First)

For this to work we need to a fake implementation of IDBSet. I’ve borrowed this one from Rowan Millar:

public class FakeDbSet<T> : IDbSet<T>
    where T : class
{
    HashSet<T> _data;
    IQueryable _query;

    public FakeDbSet()
    {
        _data = new HashSet<T>();
        _query = _data.AsQueryable();
    }

    public virtual T Find(params object[] keyValues)
    {
        throw new NotImplementedException("Derive from FakeDbSet<T> and override Find");
    }

    public void Add(T item)
    {
        _data.Add(item);
    }

    public void Remove(T item)
    {
        _data.Remove(item);
    }

    public void Attach(T item)
    {
        _data.Add(item);
    }
    public void Detach(T item)
    {
        _data.Remove(item);
    }
    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();
    }
}

Now you’ve got a fake IDBSet you can create a simple test for our controller. I’ve used NUnit and Moq.

[Test]
public void IndexReturnsList()
{
    // Create fake data
    var inMemoryItems = new FakeDbSet<Foos>
    {
        new Foo {Id = 1, Title = "One"},
        new Foo {Id = 2, Title = "Two"},
        new Foo {Id = 3, Title = "Three"},
        new Foo {Id = 4, Title = "Four"}
    };

    // Create mock unit of work
    var mockData = new Mock<IContext>();
    mockData.Setup(m => m.Foos).Returns(inMemoryItems);

    // Setup controller
    var homeController = new HomeController(mockData.Object);

    // Invoke
    var viewResult = homeController.Index();
    var foosFromView = (IEnumerable<Foo>)viewResult.Model;

    // Assert
    Assert.NotNull(foosFromView);
    Assert.AreEqual(4, foosFromView.Count());
    Assert.AreEqual(1, foosFromView.First().Id);
}

And there you have it. Everything is tested, and we didn’t need a repository.

Using Database First in Entity Framework

My implementation of database first is based on this article by Scott Allen.

A mockable data context (EF Database First)

When you use the database first wizard the code generated for you is not so easy to mock. So you need to wrap it in a mockable wrapper. Here is an example:

public interface IContext
{
    IObjectSet<Foo> Foos { get; }
    IObjectSet<Bar> Bars { get; }

    void SaveChanges();
}

Here is the wrapper implementation:

public class EFContext : IContext
{
    private readonly EFEntities _data;

    public EntityFrameworkUnitOfWork()
    {
        _data = new EFEntities();
    }

    public IObjectSet<Foo> Foos
    {
        get
        {
            return _data.CreateObjectSet<Foo>();
        }
    }

    public IObjectSet<Bar> Bars
    {
        get
        {
            return _data.CreateObjectSet<Bar>();
        }
    }

    public void SaveChanges()
    {
        _data.SaveChanges();
    }
}

Using you mockable context in a controller (EF Database First)

This is exactly the same as with code first, but I've included it again for completeness. As I said before it's very easy. I’d recommend using a proper dependency injection framework like AutoFac, but in this example I’m going to use to use poor mans DI to keep it simple.

public class HomeController
{
    private IContext _data { get; set; }

    public HomeController(IContext dataContext = null)
    {
        _data = dataContext ?? new EFContext();
    }

    public ViewResult Index()
    {
        var items = _data.Foos
                .Include(f => f.FooBit)
                .ToList();

        return View(items);   
    }
}

The nice thing here is we’ve been able to specify that we want to bring down information from the related entity FooBit. This means our view can show information from both the list of Foo objects and all the separate FooBits without creating a N+1 problem.

Unit testing our controller (EF Database First)

For this to work we need to a fake implementation of IObjectSet. I’ve borrowed this one from Scott Allen:

public class InMemoryObjectSet<T> : IObjectSet<T> where T : class
{
    public InMemoryObjectSet()
        : this(Enumerable.Empty<T>())
    {
    }

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

    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<T> GetEnumerator()
    {
        return _set.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }

    readonly HashSet<T> _set;
    readonly IQueryable<T> _queryableSet;
}

Now you’ve got a fake IObjectSet  you can create a simple test for our controller. I’ve used NUnit and Moq.

[Test]
public void IndexReturnsList()
{
    // Create fake data
    var fooList = new List<Foo>
    {
        new Foo {Id = 1, Name = "One"},
        new Foo {Id = 2, Name = "Two"},
        new Foo {Id = 3, Name = "Three"},
        new Foo {Id = 4, Name = "Four"}
    };
    var inMemoryItems = new InMemoryObjectSet<Foo>(fooList);

    // Create mock unit of work
    var mockData = new Mock<IContext>();
    mockData.Setup(m => m.Foos).Returns(inMemoryItems);

    // Test
    var homeController = new HomeController(mockData.Object);

    // Invoke
    var viewResult = homeController.Index();
    var foosFromView = (IEnumerable<Foo>)viewResult.Model;

    // Assert
    Assert.NotNull(foosFromView);
    Assert.AreEqual(4, foosFromView.Count());
    Assert.AreEqual(1, foosFromView.First().Id);
}

And there you have it. Everything is tested, and we didn’t need a repository. It was a bit trickier with database first, but not much.

What about query logic?

Another reason to use a repository is to centralise your query logic that might be needed by various controllers. In my next post I will show you how to store your query logic in extension methods.

11 Comments

  • Lauri Saar said

    Hi,

    What is the simplest way to update existing entities behind given IContext interface?

    Br,
    Lauri

  • Richard said

    @Lauri, all entities retrieved through the IContext interface are still hooked up to the real Entity Framework context and the IContext has a SaveChanges method.

    So, you can update and save changes in the same way you would if you were using the context directly.

    The nice thing about this pattern is it doesn't really hide anything.

  • Lauri Saar said

    Can you give an example? I do not have access to DbContext.Entry() method and I'm not using UpdateModel/TryUpdateModel method because data access is let's say in service layer.

  • Richard said

    @Lauri, I've never needed to use the Entry method. TryUpdateModel has always served me well. If you do need the Entry method, then I'd probably just extend the IContext interface to include this method.

  • Lauri Saar said

    Yes, interface can be extended. But in this case have you any thoughts about testability regarding to code that uses Entry method? Or any other reader of this post?

  • Leonard said

    Hello,

    I'm having a cast problem trying to instantiate the controller with the mocked object.

    System.InvalidCastException: Unable to cast object of type 'Castle.Proxies.IContextProxy' to type 'Test.Models.Context'.

    I omitted the correct project names for the sake of readability, but that is it... very strange.

  • Richard said

    @Leonard I've not covered how to set up your IOC container in this post. It looks like that is your problem. Castle needs to know about the IContext and what to resolve it to. If you've done that, then you're probably best taking your problem to Stack Overflow.

  • Jori said

    I used this along with FakeDbSet (http://nuget.org/packages/FakeDbSet) to remove our redundant repository layer. Thanks for the detailed post!

  • Robert said

    How do you feel about the Onion Architecture?
    http://jeffreypalermo.com/blog/the-onion-architecture-part-1/

    If you use your approach, then your domain objects assembly still need an outside dependency (Entity Framework, where the DbContext class is), which is a violation of the onion architecture. Would say the tradeoff of being "closer" to the DAL is worth it, even though you loose the looser coupling that the Onion Architecture provides?

  • Richard said

    @Robert I think you can use this method and still stay true to the Onion Architecture.

    You just need to keep the data context class and interface in a separate assembly from the domain model objects.

    You may also want to create view model objects so your view is not coupled to your domain objects and the view can only see what it needs to.

Comments have been disabled for this content.