Entity framework 6 mocking include method on dbset

user486523 picture user486523 · Nov 15, 2013 · Viewed 19.3k times · Source

Have been googling for a solution to the problem on how to mock the include method on dbset in EF6. The problem is well documented here :-

http://entityframework.codeplex.com/discussions/461731

Unfortunately though there does not seem to be a valid solution in there.

Has anyone found a workaround to this?

I do understand that we shouldn't really be mocking the EF6 context, but the project lead has insisted on it.

Thanks in advance.

Answer

Clint picture Clint · Feb 24, 2014

I had the same drama as @GetFuzzy above - it seemed that no matter what I did I couldn't avoid the NullReferenceException whenever an Include() call was made on a Moq DbSet. The Github example in the other answer unfortunately did not work: Set.Include() always returns null.

After fiddling for a while I came up with a workaround for this.

[Test]
public void CanUseIncludeWithMocks()
{
    var child = new Child();
    var parent = new Parent();
    parent.Children.Add(child);

    var parents = new List<Parent> { parent };
    var children = new List<Child> { child };

    var parentsDbSet1 = new FakeDbSet<Parent>();
    parentsDbSet1.SetData(parents);

    var parentsDbSet2 = new FakeDbSet<Parent>();
    parentsDbSet2.SetData(parents);

    parentsDbSet1.Setup(x => x.Include(It.IsAny<string>())).Returns(parentsDbSet2.Object);

    // Can now test a method that does something like: context.Set<Parent>().Include("Children") etc
}


public class FakeDbSet<T> : Mock<DbSet<T>> where T : class
{
    public void SetData(IEnumerable<T> data)
    {
        var mockDataQueryable = data.AsQueryable();

        As<IQueryable<T>>().Setup(x => x.Provider).Returns(mockDataQueryable.Provider);
        As<IQueryable<T>>().Setup(x => x.Expression).Returns(mockDataQueryable.Expression);
        As<IQueryable<T>>().Setup(x => x.ElementType).Returns(mockDataQueryable.ElementType);
        As<IQueryable<T>>().Setup(x => x.GetEnumerator()).Returns(mockDataQueryable.GetEnumerator());
    }
}

I really don't like the clumsiness of having to have two fake DbSets but for some reason this doesn't work:

parentsDbSet1.Setup(x => x.Include(It.IsAny<string>())).Returns(parentsDbSet1.Object);

anyone have an explanation for this?