2

我有正在测试的代码,基本上看起来像这样(具体代码对问题并不重要。它只是为了解释目的):

public ICollection<Product> GetByCategory(string category, ISession session)
{
    return session
        .CreateCriteria(typeof(Product))
        .Add(Restrictions.Eq("Category", category))
        .List<Product>();
}

这使用方法链接(我正在寻找的解决方案也适用于流利的接口语法)。

我对仅针​​对这个特定示例寻找解决方案不感兴趣,我对解决更普遍的问题感兴趣。在这个例子中,我只想为 CreateCriteria 添加一个期望值。但是,如果我这样做,我会得到一个 NullReferenceException,即使我让 CreateCriteria 返回一个存根,因为 Add 方法返回 null。

我希望我的测试继续工作,即使附加方法被链接,或者 Add 方法被删除。

在使用方法链接时,是否有一个通用技巧可以将测试双打/预期调用的数量降低到我想要断言的那些?

我能想到的一个解决方案是制作一个 T4 模板,它枚举一个类型的所有方法,并创建一个存根,其期望给出不同的默认返回值。但我想知道是否有更简单的选择。

我正在使用 Rhino.Mocks,但一般的解决方案会更受欢迎。

4

2 回答 2

1

一种可能的方法是将模拟对象包装在 DynamicProxy 中,该对象始终返回this作为流式 API 的一部分且没有记录期望的方法。它将期望已被记录(或不是流式接口的一部分)的方法委托给普通模拟对象。

检测哪些方法定义了期望当然是高度依赖于 MockLibrary 的。非流利的方法可以很容易地使用内省进行测试。

也许其中一个库已经内置了这个?

于 2010-09-03T19:28:26.457 回答
1

IQuery对于 NHibernate界面,我需要类似的东西。我将 Castle.DynamicProxy 和 Rhino.Mocks 与以下 Fake IRepository 实现一起使用...

internal class FakeRepository<TTypeOfModel> : IRepository<TTypeOfModel>
{
    ....

    public IQuery GetNamedQuery(string queryName)
    {
        return MockFactory.MockWithMethodChainingFor<IQuery>();
    }

    ....
}

internal static class MockFactory
{
    public static T MockWithMethodChainingFor<T>()
        where T : class
    {
        var generator = new ProxyGenerator();

        return generator.CreateInterfaceProxyWithTargetInterface(
            MockRepository.GenerateMock<T>(),
            new MethodChainingMockInterceptor<T>());
    }
}

internal class MethodChainingMockInterceptor<T> : StandardInterceptor
{
    protected override void PerformProceed(IInvocation invocation)
    {
        if ((Type)invocation.Method.ReturnType == typeof(T))
        {
            invocation.ReturnValue = invocation.Proxy;
        }
        else
        {
            base.PerformProceed(invocation);
        }
    }
}
于 2011-08-10T10:59:20.907 回答