我的应用程序正在使用Rhino.Commons - NHRepository和UnitOfWork。我喜欢事务的With.Transaction()语法,并且已经使用了一段时间。
但我遇到了一个问题 - 如何模拟UnitOfWork进行测试?特别是这给我带来了麻烦:
With.Transaction(() => Repositories.TwinfieldSpooler.Update(spool));
我可以使用Rhino.Mocks模拟存储库,但是如何轻松地为这种代码模拟UnitOfWork呢?
答案 0 :(得分:3)
With.Transaction使用UnitOfWork.Current属性。 UnitOfWork是一个静态类 - 你不能用RhinoMocks来模拟它。
UnitOfWork.Current是一个公共静态属性,因此您可以将其交换掉。不幸的是,setter是内部的。
我看到3个选项:
修改Rhino.Commons源以生成UnitOfWork.Current setter 公开,并在单元测试中设置。
使用反射将UnitOfWork.Current设置为假单位 工作。
由于UnitOfWork.Current在内部使用Local.Data来查找当前 交易,你应该可以 去:
Rhino.Commons.Local.Data [UnitOfWork.CurrentUnitOfWorkKey] = myFakeUnitOfWork;
有一个好消息是UnitOfWork.Current是一个IUnitOfWork,RhinoMocks可以很容易地伪造接口。
我必须说完,我对Rhino.Commons不是很熟悉,所以Ayende可能已经构建了伪造UnitOfWork的正确方法。如果这对你来说非常重要,你应该在Rhino讨论小组中提问。
答案 1 :(得分:3)
我有类似的需求,因为我想测试围绕持久性的逻辑而不实际测试数据的持久性。我发现我可以在我的测试的SetUp部分中使用这两行轻松地模拟/存根UnitOfWork
:
IUnitOfWork theStubUnitOfWork = MockRepository.GenerateStub<IUnitOfWork>();
UnitOfWork.RegisterGlobalUnitOfWork(theStubUnitOfWork);
答案 2 :(得分:0)
谢谢,但我实际上已经决定忽略对Rhino基础架构的嘲弄。 我发现Ayende http://ayende.com/Blog/archive/2009/04/28/nhibernate-unit-testing.aspx的这篇文章使用了每次测试重建的sqlite数据库。这是一个很好的解决方案!
答案 3 :(得分:0)
其他人的另外一点信息:Ogre Psalm33已经提到了如何存根UnitOfWork,但是如果你也希望With.Transaction工作,你还可以存根RhinoTransaction:
IUnitOfWork stubUnitOfWork = MockRepository.GenerateStub<IUnitOfWork>();
RhinoTransaction stubTx = MockRepository.GenerateStub<RhinoTransaction>();
stubUnitOfWork.Expect(x => x.BeginTransaction(System.Data.IsolationLevel.Unspecified)).IgnoreArguments().Return(stubTx);
UnitOfWork.RegisterGlobalUnitOfWork(stubUnitOfWork);
我记得看到Ayende某处的一张纸条,他通常只使用With.Transaction作为最后的手段,当他无法使用他喜欢的Castle Automatic Transaction Management时。