Search code examples
unit-testingdbset

Mocking DbSet<T> with RhinoMocks and EF6


I am getting this error when I run my test: System.NotImplementedException : The member 'IQueryable.Provider' has not been implemented on type 'DbSet' ...' I saw this blog post on creating a fakeDbSet but that was before EF6. Is there a better way to handle this with EF 6?

[Test]
public void Edit_ShouldCall_DbContext_Entry()
{
        //arrange
    var request = Builder<EditGroupRequest>.CreateNew().Build();
    fakeDbSet.Stub(x => x.FirstOrDefault(y => y.ReportGroupNameKey == request.Key)).Return(new MyObject());

    //act
    _sut.Edit(request);

    //assert
    _contextFake.AssertWasCalled(x => x.Entry(Arg<MyObject>.Is.Anything).Property(y => y.ReportGroupName).CurrentValue = request.Name);
}

Solution

  • Although DBSet implements IQueryable, IDbSet... the object generated by the mock engine is not implementing them.

    A possible solution is using a Mocking framework that supports building mocks that implement many interfaces like the one pointed out in another thread (Substitute): Mocking DBSet, EF Model First

    Here you have an utility function to build a mocked DBSet which data is stored on a generic list:

    public static DbSet<T> BuildMockedDbSet<T>(List<T> data) where T : class
        {
            IQueryable<T> queryable = data.AsQueryable();
            DbSet<T> fakeDbSet = Substitute.For<DbSet<T>, IQueryable<T>>();
            ((IQueryable<T>)fakeDbSet).Provider.Returns(queryable.Provider);
            ((IQueryable<T>)fakeDbSet).Expression.Returns(queryable.Expression);
            ((IQueryable<T>)fakeDbSet).ElementType.Returns(queryable.ElementType);
            ((IQueryable<T>)fakeDbSet).GetEnumerator().Returns(queryable.GetEnumerator());
            fakeDbSet.AsNoTracking().Returns(fakeDbSet);
            return fakeDbSet;
        }
    

    Hope it helps.