Let’s face it, EntityFramework is a pain to mock. With few interfaces, testing things that use it can be a real pain. Here’s a few things I’ve found to make it easier:
- Make sure that you have an interface for your DbContext object so that it can easily be mocked. If you’re doing Database First, be aware that EF 7 will eliminate EDMX support, so welcome to the code first era (I hear you . . .).
- Rather than using your Dependency Injector to directly inject an instance of your IDbContext, create a context provider instead. This will make testing easier since you can easily mock the provider. Something like IMyContext context = IContextProvider.GetContext(); where IContextProvider is injected. You can also easily set things like lazy loading and dynamic proxy generation, both of which are useless for anything that doesn’t have direct access to the database.
- Make sure you’re using IDbSet instead of DbSet
With all of that in place, you can do some really fun stuff. Here’s a method that I use to setup a DbSet that is backed by a List, and is attached to the context:
protected Mock> SetupDbSet(IList dataSource, Mock context) where T : class
{
Mock> set = new Mock>();
set.As>().Setup(drs => drs.Provider).Returns(dataSource.AsQueryable().Provider);
set.As>().Setup(drs => drs.Expression).Returns(dataSource.AsQueryable().Expression);
set.As>().Setup(drs => drs.ElementType).Returns(dataSource.AsQueryable().ElementType);
set.As>().Setup(drs => drs.GetEnumerator()).Returns(dataSource.AsQueryable().GetEnumerator());
set.Setup(s => s.Add(It.IsAny())).Callback(dataSource.Add);
set.Setup(s => s.Remove(It.IsAny())).Callback((i) => dataSource.Remove(i));
Type type = typeof(IDbSet);
Type contextType = typeof(IMyDbContext);
var parameter = System.Linq.Expressions.Expression.Parameter(contextType);
PropertyInfo info = contextType.GetProperties().First(pi => pi.PropertyType == type);
var body = System.Linq.Expressions.Expression.Property(parameter, info);
dynamic func = System.Linq.Expressions.Expression.Lambda(body, parameter);
context.SetupProperty>(func, set.Object);
return set;
}
With that method, all you need to do is the following:
IList myEntities = new List();
// add entities
this.SetupDbSet(myEntities, mydbContextMock):
With those two lines of code, you’ll have mocked data in your context wherever it’s needed and be able to easily get to the changes made to the dbset.
Enjoy!