我的测试代码基本上看起来像这样(具体代码对问题并不重要。这只是出于解释目的):
public ICollection<Product> GetByCategory(string category, ISession session)
{
return session
.CreateCriteria(typeof(Product))
.Add(Restrictions.Eq("Category", category))
.List<Product>();
}
这使用方法链(我正在寻找的解决方案也适用于fluent interface syntax)。
我对找到这个具体例子的解决方案不感兴趣,我有兴趣解决一个更普遍的问题。在这个例子中,我只想添加对CreateCriteria的期望。但是,如果我这样做,我会得到一个NullReferenceException,即使我让CreateCriteria返回一个存根,因为Add方法返回null。
我希望我的测试能够继续工作,即使链接了其他方法,或者删除了Add方法。
在使用方法链时,是否有一个通用技巧可以将测试双打/预期调用的数量减少到我想要断言的那些?
我能想到的一个解决方案是创建一个枚举类型上所有方法的T4模板,并创建一个期望的存根,提供不同的默认返回值。但我想知道是否有更简单的选择。
我正在使用Rhino.Mocks,但一般的解决方案会更受欢迎。
答案 0 :(得分:1)
一种可能的方法是将模拟对象包装在DynamicProxy中,该方法总是为方法返回this
,这些方法是流畅的API的一部分,没有记录的预期。它委托给普通的模拟对象,用于记录期望的方法(或者不是流畅界面的一部分)。
检测哪些方法具有预期定义当然将取决于MockLibrary。使用内省可以轻松测试非流畅的方法。
也许其中一个图书馆已经建成了这个?
答案 1 :(得分:1)
对于NHibernate IQuery
接口我需要这样的东西。我使用了Castle.DymanicProxy和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);
}
}
}