如何用持久性无知进行单元测试

时间:2011-07-05 18:51:32

标签: asp.net-mvc unit-testing nhibernate repository persistence-ignorance

我正在开展一个新项目,我正积极努力追求持久性的无知。例如,在我的服务层中,我从我的ORM中检索实体,并调用在实体上定义的例程,该例程可能会也可能不会对实体进行更改。然后我依靠我的ORM来检测实体是否被修改,并进行必要的插入/更新/删除。

当我运行应用程序时,它按预期工作,看到这个实际上非常简洁。我的业务逻辑非常孤立,我的服务层非常薄。

当然,现在我正在添加单元测试,我注意到我不能再编写单元测试来验证某些属性是否被修改。在我之前的解决方案中,我确定是否在对象处于预期状态的情况下进行了存储库调用。

mockRepository.Verify(mr => 
  mr.SaveOrUpdate(It.Is<MyEntity>(x => 
    x.Id == 123 && x.MyProp == "newvalue")), Times.Once());

我是否正确接近持久性无知?当我没有明确调用存储库的保存方法时,是否有更好的方法对我的实体的操作后状态进行单元测试?

如果有帮助,我正在使用ASP.NET MVC 3,WCF,NHibernate和NUnit / Moq。我的单元测试调用我的控制器操作传递我的服务类的实例(用模拟的存储库实例化)。

2 个答案:

答案 0 :(得分:0)

您正在接近这个,因为您有一个代表您的存储库的接口并在测试中传入假,我更喜欢使用内存模拟器来存储我的存储库而不是使用模拟因为我发现存根实现倾向于使我的测试比使用mock / verify更简单(因为模拟不是上面链接的存根文章)。如果您的存储库有Add / Find / Delete方法,我的内存实现会将它们转发到成员列表,然后save将设置一个名为SavedList的属性,我可以在我的测试中断言。

答案 1 :(得分:0)

奇怪的是,我偶然发现了一个解决方案而且非常简单。

[Test]
public void Verify_Widget_Description_Is_Updated()
{
  // arrange
  var widget = new Widget { };
  mockWidgetRepo.Setup(mr => mr.GetWidget()).returns(widget);

  var viewModel = new WidgetVM { };
  viewModel.Description = "New Desc";  

  // act
  var result = (ViewResult)controller.UpdateWidget(viewModel);

  // assert
  Assert.AreEqual("New Desc", widget.Description);
}

这并不完美,但我可以假设如果widget.Description与我分配给我的视图模型的值相匹配,那么除非调用evict,否则ORM会保存该更改。

<强>更新 刚刚提出了另一种替代解决方案。我在我的基础存储库中创建了一个ObjectStateAssertionForTests(Object obj)函数,它什么都不做。我可以在我的代码中调用此函数,然后在单元测试中检查它。

mockRepository.Verify(mr => 
  mr.ObjectStateAssertionForTests(It.Is<MyEntity>(x => 
    x.Id == 123 && x.MyProp == "newvalue")), Times.Once());