How to Mock an Entity Framework DbContext and DbSet with Moq

If you find yourself in a situation where you need to mock a DbContext and DbSet with the Moq framework, it is easy to do. However, there are a couple of “gotchas” I found out recently.

Let’s assume the following simplified MyEntity, MyEntityRepository, and MyDbContext classes:

    public class MyEntity
    {
        public string Name { get; set; }
    }

    // Provides a repository for MyEntity objects.
    public class MyEntityRepository
    {
        private Func<MyDbContext> createContext;

        // Initializes a new instance of the MyEntityRepository class using
        // the specified DbContext factory method.
        public MyEntityRepository(Func<MyDbContext> createContext)
        {
            this.createContext = createContext;
        }

        // Gets all the entities with the specified name.
        public IEnumerable<MyEntity> GetMyEntities(string name)
        {
            using (var context = this.createContext())
            {
                return context.MyEntities
                    .Where(myEntity => myEntity.Name == name)
                    .ToArray();
            }
        }
    }

    public class MyDbContext : DbContext
    {
        public virtual DbSet<MyEntity> MyEntities { get; set; }
    }

We want to write a unit test for the MyEntityRepository.GetMyEntities(string name) method, to ensure it is filtering entities correctly. We can accomplish this with a test method that looks similar to the following:

        // Tests that the MyEntityRepository can get entities by a name.
        [TestMethod]
        public void CanGetEntitiesByAName()
        {
            // Initialize a list of MyEntity objects to back the DbSet with.
            var myEntities = new List<MyEntity>()
            {
                new MyEntity() { Name = "Entity1" },
                new MyEntity() { Name = "Entity1" },
                new MyEntity() { Name = "Entity2" }
            };

            // Create a mock DbContext.
            var dbContext = new Mock<MyDbContext>();

            // Create a mock DbSet.
            var dbSet = new Mock<DbSet<MyEntity>>();

            // Set up the MyEntities property so it returns the mocked DbSet.
            dbContext.Setup(o => o.MyEntities).Returns(dbSet.Object);

            // Set up the DbSet as an IQueryable so it can be enumerated.
            var queryable = myEntities.AsQueryable();
            dbSet.As<IQueryable<MyEntity>>().Setup(m => m.Provider).Returns(queryable.Provider);
            dbSet.As<IQueryable<MyEntity>>().Setup(m => m.Expression).Returns(queryable.Expression);
            dbSet.As<IQueryable<MyEntity>>().Setup(m => m.ElementType).Returns(queryable.ElementType);
            dbSet.As<IQueryable<MyEntity>>().Setup(m => m.GetEnumerator()).Returns(() => queryable.GetEnumerator());

            var uut = new MyEntityRepository(() => dbContext.Object);
            var results = uut.GetMyEntities("Entity1");

            Assert.AreEqual(2, results.Count());
        }

Seems pretty straightforward, but it doesn’t work. When ran in the test runner, you are presented with this error:

Test method CodingOnCaffeine.MyEntityRepositoryTests.CanGetEntitiesByAName threw exception: 
System.NotImplementedException: The member 'IQueryable.Provider' has not been implemented on type 'DbSet`1Proxy' which inherits from 'DbSet`1'. Test doubles for 'DbSet`1' must provide implementations of methods and properties that are used.

Because of the way Moq’s underlying proxies work, the IQueryable methods and property set ups never made it on the underlying Mock proxy exposed by the MyDbContext.MyEntities property. We can address this by simply using a lambda expression when we set up the MyDbContext.MyEntities property.

        // Tests that the MyEntityRepository can get entities by a name.
        [TestMethod]
        public void CanGetEntitiesByAName()
        {
            // Initialize a list of MyEntity objects to back the DbSet with.
            var myEntities = new List<MyEntity>()
            {
                new MyEntity() { Name = "Entity1" },
                new MyEntity() { Name = "Entity1" },
                new MyEntity() { Name = "Entity2" }
            };

            // Create a mock DbContext.
            var dbContext = new Mock<MyDbContext>();

            // Create a mock DbSet.
            var dbSet = new Mock<DbSet<MyEntity>>();

            // Set up the MyEntities property so it returns the mocked DbSet.
            dbContext.Setup(o => o.MyEntities).Returns(() => dbSet.Object);

            // Set up the DbSet as an IQueryable so it can be enumerated.
            var queryable = myEntities.AsQueryable();
            dbSet.As<IQueryable<MyEntity>>().Setup(m => m.Provider).Returns(queryable.Provider);
            dbSet.As<IQueryable<MyEntity>>().Setup(m => m.Expression).Returns(queryable.Expression);
            dbSet.As<IQueryable<MyEntity>>().Setup(m => m.ElementType).Returns(queryable.ElementType);
            dbSet.As<IQueryable<MyEntity>>().Setup(m => m.GetEnumerator()).Returns(() => queryable.GetEnumerator());

            var uut = new MyEntityRepository(() => dbContext.Object);
            var results = uut.GetMyEntities("Entity1");

            Assert.AreEqual(2, results.Count());
        }

The test passes now since the IQueryable methods and properties are set up correctly on the underlying proxy, and the proxy is reevaluated by the lambda expression when the MyDbContext.MyEntities is accessed in the test.

With such a complex set up for a mock DbSet, this code could be refactored to be a little more reusable. Let’s create a factory to help with this.

    // Provides a way to create mock DbSets
    public static class MockDbSetFactory
    {
        // Creates a mock DbSet from the specified data.
        public static Mock<DbSet<T>> Create<T>(IEnumerable<T> data) where T : class
        {
            var queryable = data.AsQueryable();
            var mock = new Mock<DbSet<T>>();
            mock.As<IQueryable<T>>().Setup(m => m.Provider).Returns(queryable.Provider);
            mock.As<IQueryable<T>>().Setup(m => m.Expression).Returns(queryable.Expression);
            mock.As<IQueryable<T>>().Setup(m => m.ElementType).Returns(queryable.ElementType);
            mock.As<IQueryable<T>>().Setup(m => m.GetEnumerator()).Returns(() => queryable.GetEnumerator());

            return mock;
        }
    }

With this factory, the test looks much easier to read. It also alleviates the need to use a lambda expression in the Returns() method setup on the MyDbContext mock, since the mock DbSet is fully created in a single function call.

        // Tests that the MyEntityRepository can get entities by a name.
        [TestMethod]
        public void CanGetEntitiesByAName()
        {
            // Initialize a list of MyEntity objects to back the DbSet with.
            var myEntities = new List<MyEntity>()
            {
                new MyEntity() { Name = "Entity1" },
                new MyEntity() { Name = "Entity1" },
                new MyEntity() { Name = "Entity2" }
            };

            // Create a mock DbContext.
            var dbContext = new Mock<MyDbContext>();

            // Create a mock DbSet.
            var dbSet = MockDbSetFactory.Create(myEntities);

            // Set up the MyEntities property so it returns the mocked DbSet.
            dbContext.Setup(o => o.MyEntities).Returns(dbSet.Object);

            var uut = new MyEntityRepository(() => dbContext.Object);
            var results = uut.GetMyEntities("Entity1");

            Assert.AreEqual(2, results.Count());
        }

Hopefully after reading this you guys won’t be spinning your wheels as long as I did trying to figure out why your mock DbSet wasn’t being set up, even though you thought it was. Cheers.