你的测试试图达到什么目的?
您正在验证什么行为或状态?具体来说,您是在验证协作者(数据)是否正在ListCount
调用其方法(基于交互的测试),还是只想ListCount
返回一个固定值以驱动被测类,同时在其他地方验证结果(基于传统状态的测试) ?
如果要设置期望,请使用模拟和期望:使用MockRepository.CreateMock<IMyInterface>()
和myMock.Expect(x => x.ListCount())
如果要存根方法,请使用MockRepository.CreateStub<IMyInterface>()
and myStub.Stub(x => x.ListCount())
。
(除此之外:我知道您可以使用 stub.AssertWasCalled() 来实现与 mock.Expect 大致相同的事情,并且可以使用更好的阅读语法,但我只是在深入研究模拟和存根之间的区别)。
Roy Osherove 对模拟和存根有很好的解释。
请发布更多代码!
我们需要全面了解您如何创建存根(或模拟)以及如何将结果用于被测类。ListCount
有输入参数吗?如果有,它代表什么?您是否关心它是否以特定值调用?您是否关心是否ListCount
返回某个值?
正如 Simon Laroche 指出的那样,如果 Manager 实际上没有对 ListCount 的模拟/存根返回值做任何事情,那么测试将不会因此而通过或失败。测试所期望的只是调用了模拟/存根方法——仅此而已。
为了更好地理解这个问题,考虑三个信息,你很快就会明白这一点:
- 正在测试什么
- 在什么情况下?
- 预期的结果是什么?
比较:
使用模拟进行基于交互的测试。模拟呼叫是测试。
[Test]
public void calling_ListCount_calls_ListCount_on_DAL()
{
// Arrange
var dalMock = MockRepository.Mock<IDAL>();
var dalMock.Expect(x => x.ListCount()).Returns(1);
var manager = new Manager(dalMock);
// Act
manager.ListCount();
// Assert -- Test is 100% interaction based
dalMock.VerifyAllExpectations();
}
带有存根的基于状态的测试。存根驱动测试,但不是预期的一部分。
[Test]
public void calling_ListCount_returns_same_count_as_DAL()
{
// Arrange
var dalStub = MockRepository.Stub<IDAL>();
var dalStub.Stub(x => x.ListCount()).Returns(1);
var manager = new Manager(dalMock);
// Act
int listCount = manager.ListCount();
// Assert -- Test is 100% state based
Assert.That(listCount, Is.EqualTo(1),
"count should've been identical to the one returned by the dal!");
}
我个人倾向于尽可能地进行基于状态的测试,尽管基于交互的测试通常需要使用Tell, Don't Ask设计的 API ,因为您不会有任何暴露的状态需要验证!
API 混乱。模拟不是存根。还是他们?
rhino mocks 中的 mock 和 stub 之间的区别是混乱的。传统上,存根并不意味着有期望——所以如果你的测试替身没有调用它的方法,这不会直接导致测试失败。
... 然而,Rhino Mocks API 功能强大,但令人困惑,因为它让您对存根设定期望,对我来说,这与公认的术语背道而驰。我也不在意这些术语。在我看来,如果消除这种区别并且在测试中调用的方法可以起到双重作用,那就更好了。