正如标题所说,我按照模型第一种方法。 所以我的模型类是自动生成的。 如果我想嘲笑DBContext
派生MyModelContainer
包含DBSets
实体类的。 看了一些地方,为了进行单元测试,则需要将其更改为IDBSet
。 无论是其能够做到这一点尤其是在一类获取,当我做“运行自定义工具”自动生成的一个问题。 但截至现在,我修改了它。
但真正的问题是:当我尝试存根MyModelContainer
返回从生成的模拟IDBSet
。 犀牛模拟射击是一个InvalidOperationException:“无效的调用,最后调用已被使用,或者没有来电的情况下(请确保您调用虚拟(C#)/可重写(VB)的方法。”
这里是我的单元测试代码。
MyModelContainer dbMock = MockRepository.GenerateMock<MyModelContainer>();
IDBSet<Models.MyEntity> entityMock = MockRepository.GenerateMock<IDBSet<Models.MyEntity>>()
dbMock.Stub( x=>x.MyEntities ).Return( entityMock );
最后陈述引发的异常。 我试着使用假落实IDBSet<>
指定位置 ,但没有运气!
我使用MVC 4,犀牛制品3.6。 任何帮助将不胜感激。
更新:
一些试验和研究之后,我找到了解决。 我改变了代码:
MyModelContainer dbMock = MockRepository.GenerateMock<MyModelContainer>();
IDBSet<Models.MyEntity> entityMock = MockRepository.GenerateMock<IDBSet<Models.MyEntity>>()
//dbMock.Stub( x=>x.MyEntities ).Return( entityMock );
dbMock.MyEntities = entityMock;
现在InvalidOperationException
已经一去不复返了。 仅仅是由于测试失败ExpectationViolationException
这应该是正常的。
至于生成的模型类汽车,它被发现,编辑DbContext's
T4模板(.TT扩展)会做的伎俩。 由于艾伦的博客
但我想知道为什么前面的代码没有工作。 任何人?
2个原因可能在这里:
MyEntites
财产MyModelContainer
不虚。
在这种情况下犀牛模拟不能在所有存根此属性。 然后dbMock.Stub(x=>x.MyEntities)
将失败。
MyEntites
财产是虚拟的,但具有公共getter和setter方法公开。
然后符号dbMock.Stub(x=>x.MyEntities).Return(entityMock)
是不允许的。 你可以看到解释如这里 。
在这两种情况下,正确的解决方法是,你做了什么:使用dbMock.MyEntities = entityMock
代替dbMock.Stub(x=>x.MyEntities).Return(entityMock)
下面是用于取代IDbSet(与NSubstitute)的扩展方法以返回一个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;
}
那么你现在可以存根像这样的DbContext:
var db = NSubstitute.Substitute.For<DataContext>();
var fakeResult = emptyCustomers.FakeDbSet();
db.Customers.Returns(fakeResult);
下面是Stubing(与RhinoMocks)IDbSet扩展方法以返回一个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;
}
}
那么你现在可以存根像这样的DbContext:
_db.Stub(p => p.Customers).Return(fakeCustomers.MockToDbSet());