Rhino Mocks:实例化 Mock 属性,以便 Expectation 可以引用它

Posted

技术标签:

【中文标题】Rhino Mocks:实例化 Mock 属性,以便 Expectation 可以引用它【英文标题】:Rhino Mocks: Instantiating Mock property so Expectation can reference it 【发布时间】:2011-06-07 19:31:34 【问题描述】:

我正在编写一个带有模拟的单元测试,但我无法成功编写它。其中一个属性是一个集合,我需要在为模拟设置期望时引用它。现在期望语句抛出一个空值。大致是这样的。

IFoo myMock = MockRepository.GenerateMock<IFoo>();
List<Entity> col = new List<Entity>();
Entity entity = new Entity();

myMock.Expect(p => p.FooCollection).Return(col);
myMock.Expect(p => p.FooCollection.Add(entity)); // throws null exception here

我是 rhino mocks 的新手,感觉我做的不对。还有其他方法可以正确实例化集合吗?可能没有我上面的期望?

更新 我认为我遇到了问题,因为我定义的接口将集合指定为只读。

interface IFoo

    List<Entity> FooCollection  get; 

【问题讨论】:

【参考方案1】:

我对 Rhino Mocks 并不太熟悉,但我认为在您致电 .Replay() 之前,您的期望并没有实际上挂钩 - 您在示例中暗示的模拟方法看起来更像Moq 给我。

也就是说,我认为您在这里做的事情根本上是错误的。你到底想测试什么?是p 对象,还是List&lt;Entity&gt; 上的某个对象?如果您真正想要测试的是p.YourMethodUnderTest() 实际将entity 添加到集合中,您可能只想设置p.FooCollection 以返回您的列表,然后验证您的列表是否包含实体对象。

// Arrange
IFoo myMock = MockRepository.GenerateMock<IFoo>();
List<Entity> col = new List<Entity>();
Entity entity = new Entity();

myMock.Expect(p => p.FooCollection).Return(col);
// myMock.Expect(p => p.FooCollection.Add(entity)) - skip this

// Act
p.YourMethodUnderTest(entity);

// Assert
Assert.IsTrue(col.Contains(entity)); // Or something like that

【讨论】:

我不知道为什么我没想到!我想我对 rhino mocks 的要求太多了。非常感谢您的解决方案。 @jlafay:很高兴我能帮上忙 =)【参考方案2】:

您应该使用存根而不是模拟,例如:

IFoo myMock = MockRepository.GenerateStub<IFoo>();
myMock.FooCollection = col;

此外,您正在对一个真实对象 (collection.Add()) 设置期望,这实际上是行不通的。您可以通过将FooCollection 属性类型设置为IList 而不是具体的List 来解决此问题。

使用具体的集合类型作为参数无论如何都是一种代码味道(我建议使用 FxCop 来教你这些东西)。

【讨论】:

该集合是只读的,因此您不能像在示例中那样直接分配它。是否因为我将集合公开为属性而产生了代码异味?我可以看到将其保留为私有字段并添加 AddEntity() 方法是有益的,因为现在我回顾我的代码,其中存在耦合代码,其中客户端代码在将实体添加到集合后对其进行处理。跨度> 你对只读集合是正确的,我的代码不起作用。至于代码味道,我的意思是:***.com/questions/387937/… 我不确定我是否完全同意这个问题的主要答案,但我确实认为我需要避免暴露我的收藏。答案提到 List 臃肿而 IList 并不那么臃肿。嗯,是的,它应该是这样的。您的 IList 变量仍然指向 List,因此它的“臃肿”并不少。 通过公开IList&lt;&gt;,您实际上使实现更容易使用List&lt;&gt;以外的其他东西 - 例如Entity[]数组。这个想法是使用接口来定义合约,而不是在这些合约中强制执行细节。指定一个具体的集合类型(如List)是在没有真正需要的情况下强制执行一个实现细节。通过使用接口,您实际上可以更轻松地模拟事物。 至于您对AddEntity() 方法而不是公开集合的建议,这是一个很好的建议。参见得墨忒耳法则 (en.wikipedia.org/wiki/Law_of_Demeter)

以上是关于Rhino Mocks:实例化 Mock 属性,以便 Expectation 可以引用它的主要内容,如果未能解决你的问题,请参考以下文章

为啥我的 Rhino Mocks Partial Mock 方法调用没有被模拟?

Rhino Mocks - 使用 ref/out 参数模拟集合

Rhino Mocks 默认返回类型?

使用 Rhino Mocks 保存到存储库

如何使用 Rhino Mocks 模拟任意行为?

无法使用 Rhino Mocks 模拟具有数组参数的构造函数的类