所以我正在尝试为我的业务逻辑层编写一些测试用例。我已经模拟了我的数据访问层(返回NHibernate IQueryOver
对象)。我创建了一个实现MockQueryOver
接口的IQueryOver
类,因为我在业务逻辑层中链接函数,因此创建一个存根IQueryOver
对我来说没有意义。
无论如何,这一切都有效,但我遇到的问题是当我尝试在OrderBy()
上进行QueryOver
时。在我的MockQueryOver
课程中,我现在正在实施OrderBy()
方法:
public IQueryOverOrderBuilder<TRoot, TSubType> OrderBy(Expression<Func<TSubType, object>> path)
{
var func = path.Compile();
IList<TSubType> result = m_data.OrderBy(func).ToList();
var mockRepo = new MockRepository();
var queryOver = new MockQueryOver<TRoot, TSubType>(m_data);
IQueryOverOrderBuilder<TRoot, TSubType> mockOrderBuilder = mockRepo.StrictMock<IQueryOverOrderBuilder<TRoot, TSubType>>(queryOver, path);
mockOrderBuilder.Stub(x => x.Desc).Return(queryOver);
mockOrderBuilder.Stub(x => x.Asc).Return(queryOver);
return mockOrderBuilder;
}
问题是RhinoMocks会在任何Stub方法上抛出异常。这是例外:
System.NullReferenceException : Object reference not set to an instance of an object.
at NHibernate.Criterion.Lambda.QueryOverOrderBuilderBase`3.AddOrder(Func`2 orderStringDelegate, Func`2 orderDelegate)
at NHibernate.Criterion.Lambda.QueryOverOrderBuilderBase`3.get_Desc()
at NHibernate.Criterion.QueryOverBuilderExtensions.Desc(IQueryOverOrderBuilder`2 builder)
at BLL.Tests.Mock_Objects.MockQueryOver`2.<OrderBy>b__7(IQueryOverOrderBuilder`2 x) in MockQueryOverSubType.cs: line 239
我是NHibernate和RhinoMocks的新手,所以我不确定它在幕后做了什么,但似乎即使我正在创建一个接口的模拟,它仍然会在我尝试时调用具体的扩展方法存根方法。
有人可以澄清这个或帮我解决这个问题吗?另外,由于我刚刚开始编写这些测试用例,我不介意切换模拟框架,只要它可以免费使用。
非常感谢!
答案 0 :(得分:3)
您确定IQueryOverOrderBuilder
是一个界面吗?它似乎是a confusingly-named class that implements QueryOverOrderBuilderBase。我不完全确定在这种情况下的行为是什么,但我认为StrictMock
IQueryOverOrderBuilder
实际上正在调用那个可能没有设置的基类,并且正在抛出你看到的例外。
我想也许您可能需要在业务逻辑和NHibernate之间添加另一个抽象层,使用可以可靠地模拟的类。我不认为有一种方法可以用RhinoMocks模拟像IQueryOverOrderBuilder
这样的具体类(但如果有的话,我很乐意纠正)。
要创建另一个抽象层,请分析当前与NHibernate交互的业务逻辑中的操作,并定义一个新的函数接口来封装这些操作(例如,IRepository)。通过NHibernate向数据库添加内容的代码可能会成为名为AddItem
的接口上的函数。将与此接口后面的NHibernate交互的代码移动到新类的新函数中(没有理由说它需要成为单个类 - 您可以将逻辑相关的代码分组到具有单独接口的单独类中)。新接口可能能够引用一些可以轻松实例化或模拟的NHibernate类和接口(理想情况下,接口根本不会引用NHibernate,但是你这样做是为了测试,而不是完全解耦你的代码来自NHibernate,所以很好)。完成此操作后,可以针对新接口的模拟(或模拟)对业务逻辑进行单元测试,并且可以针对实际数据库对实现该接口的类进行集成测试。这很宽松地是Adapter pattern。如果没有确切了解您的业务逻辑的作用,就很难对设计进行进一步评论。我希望这有用。
最后,如果您要创建自己的MockRepository
,我认为您需要在您创建的模拟(或Replay()
上的ReplayAll()
)上调用MockRepository
你存根。如果从MockRepository
上的静态方法创建模拟,则无需执行此操作。似乎与您当前的问题无关(尽管如此,请在Stub
来电之后调用它,看看它是否有所不同),但我认为无论如何我都会提到它。