Mocking DBSet, EF Model First

孤者浪人 提交于 2019-12-12 08:58:47

问题


As said in the title, I follow Model First method. So my Model classes are Automatically generated. If I want mock the DBContext derived MyModelContainer which contain DBSets of entity classes. Read some where that in order to unit test, you need to change it to IDBSet. Whether its possible to do it especially in a class that gets auto generated when I do "Run Custom Tool" is one concern. But as of now I modified it.

But the real problem is: when I try to Stub MyModelContainer to return a mock generated from IDBSet. Rhino mock is firing an InvalidOperationException: "Invalid call, the last call has been used, or no call has been made(make sure that you are calling a virtual(C#)/Overridable(VB) method."

Here is my unit test code.

MyModelContainer dbMock = MockRepository.GenerateMock<MyModelContainer>();
IDBSet<Models.MyEntity> entityMock = MockRepository.GenerateMock<IDBSet<Models.MyEntity>>()
dbMock.Stub( x=>x.MyEntities ).Return( entityMock );

The last statement is triggering the exception. I tried using the fake implementation of IDBSet<> specified here, But no luck!

I use MVC 4, Rhino Mocks 3.6. Any help will be appreciated.

Update:

After some trials and research, I found a fix. I changed the code to:

MyModelContainer dbMock = MockRepository.GenerateMock<MyModelContainer>();
IDBSet<Models.MyEntity> entityMock = MockRepository.GenerateMock<IDBSet<Models.MyEntity>>()
//dbMock.Stub( x=>x.MyEntities ).Return( entityMock );
dbMock.MyEntities = entityMock;

Now the InvalidOperationException is gone. The test fails only due to ExpectationViolationException which should be normal.

As for auto generated Model class, it is found out that editing the DbContext's T4 template (.tt extension) will do the trick. Thanks to Alan's Blog

But I want to know why the previous code didn't work. Anyone?


回答1:


2 reasons are possible here:

  1. MyEntites property of MyModelContainer is not virtual.
    In that case Rhino Mock can't stub this property at all. Then dbMock.Stub(x=>x.MyEntities) will fail.

  2. MyEntites property is virtual, but has both public getter and public setter.
    Then notation dbMock.Stub(x=>x.MyEntities).Return(entityMock) is not allowed. You can see explanation e.g. here.

In both cases the right fix is exactly what you did: use dbMock.MyEntities = entityMock instead of dbMock.Stub(x=>x.MyEntities).Return(entityMock).




回答2:


Here is an extension method for Substituting IDbSet (with NSubstitute) to return an IQueryable

    public static DbSet<T> FakeDbSet<T>(this IQueryable<T> queryable) where T : class
    {
        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;
    }

Then you can now stub the DbContext like this:

        var db = NSubstitute.Substitute.For<DataContext>();
        var fakeResult = emptyCustomers.FakeDbSet();
        db.Customers.Returns(fakeResult);



回答3:


Here is an extension method for Stubing (with RhinoMocks) IDbSet to return an IQueryable

public static class RhinoExtensions
{
    public static IDbSet<T> MockToDbSet<T>(this IQueryable<T> queryable) where T : class
    {
        IDbSet<T> mockDbSet = MockRepository.GenerateMock<IDbSet<T>>();
        mockDbSet.Stub(m => m.Provider).Return(queryable.Provider);
        mockDbSet.Stub(m => m.Expression).Return(queryable.Expression);
        mockDbSet.Stub(m => m.ElementType).Return(queryable.ElementType);
        mockDbSet.Stub(m => m.GetEnumerator()).Return(queryable.GetEnumerator());
        return mockDbSet;
    }
}

Then you can now stub the DbContext like this:

_db.Stub(p => p.Customers).Return(fakeCustomers.MockToDbSet());


来源:https://stackoverflow.com/questions/15516543/mocking-dbset-ef-model-first

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!