2

所以我正在尝试为我的业务逻辑层编写一些测试用例。我已经模拟了我的数据访问层(它返回 NHibernateIQueryOver对象)。我创建了一个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 的新手,所以我不确定它在幕后做了什么,但似乎即使我正在创建一个接口的模拟,当我尝试存根时它仍然调用具体的扩展方法方法。

有人可以澄清一下或帮助我解决这个问题吗?另外,由于我刚刚开始编写这些测试用例,我不介意切换模拟框架,只要它可以免费使用。

非常感谢!

4

1 回答 1

3

你确定IQueryOverOrderBuilder是接口吗?它似乎是一个实现 QueryOverOrderBuilderBase 的命名混淆的类。我不完全确定在这种情况下的行为是什么,但我认为你实际上StrictMockIQueryOverOrderBuilder在调用那个可能没有设置的基类,并且抛出了你看到的异常。

我认为也许您可能需要在您的业务逻辑和 NHibernate 之间添加另一个抽象层,以及可以可靠地模拟的类。我认为没有办法像IQueryOverOrderBuilderRhinoMocks 那样模拟一个具体的类(但如果有的话,我很高兴得到纠正:)。

要创建另一个抽象层,请分析当前与 NHibernate 交互的业务逻辑中的操作,并定义一个新的函数接口来封装这些操作(例如,IRepository)。通过 NHibernate 向数据库添加内容的代码可能会成为名为AddItem. 将与此接口后面的 NHibernate 交互的代码移动到新类的新函数中(没有理由让它必须是单个类 - 您可以将逻辑相关的代码分组到具有单独接口的单独类中)。新接口可能能够分别引用一些可以轻松实例化或模拟的 NHibernate 类和接口(理想情况下,该接口根本不会引用 NHibernate,但您这样做是为了测试,而不是完全解耦您的代码来自NHibernate,所以很好)。完成此操作后,您的业务逻辑可以针对新接口的一个模拟(或多个模拟)进行单元测试,并且可以针对实际数据库对实现该接口的一个或多个类进行集成测试。这是,松散的,适配器模式. 如果不确切了解您的业务逻辑是做什么的,就很难对设计进行进一步评论。我希望这是有帮助的。

最后,如果您要创建自己的MockRepository,我认为您需要在对它们进行存根之后调用Replay()您创建的模拟(或在模拟ReplayAll()上)。MockRepository如果您从 上的静态方法创建模拟,则不需要这样做MockRepository。似乎与您当前的问题无关(尽管,请尝试在通话后调用它Stub,看看是否有任何区别),但我想我还是会提到它。

于 2013-06-27T16:38:56.513 回答