Rhino Mocks - Stub .Expect vs .AssertWasCalled

此生再无相见时 提交于 2019-11-28 04:21:58
Mark Simpson

What is your test trying to achieve?

What behaviour or state are you verifying? Specifically, are you verifying that the collaborator (data) is having its ListCount method called (interaction based testing), or do you just want to make ListCount return a canned value to drive the class under test while verifying the result elsewhere (traditional state based testing)?

If you want set an expectation, use a mock and an expectation: Use MockRepository.CreateMock<IMyInterface>() and myMock.Expect(x => x.ListCount())

If you want to stub a method, use MockRepository.CreateStub<IMyInterface>() and myStub.Stub(x => x.ListCount()).

(aside: I know you can use stub.AssertWasCalled() to achieve much the same thing as mock.Expect and with arguably better reading syntax, but I'm just drilling into the difference between mocks & stubs).

Roy Osherove has a very nice explanation of mocks and stubs.

Please post more code!

We need a complete picture of how you're creating the stub (or mock) and how the result is used with respect to the class under test. Does ListCount have an input parameter? If so, what does it represent? Do you care if it was called with a certain value? Do you care if ListCount returns a certain value?

As Simon Laroche pointed out, if the Manager is not actually doing anything with the mocked/stubbed return value of ListCount, then the test won't pass or fail because of it. All the test would expect is that the mocked/stubbed method is called -- nothing more.

To better understand the problem, consider three pieces of information and you will soon figure this out:

  1. What is being tested
  2. In what situation?
  3. What is the expected result?

Compare: Interaction based testing with mocks. The call on the mock is the test.

[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();   
}

State based testing with a stub. The stub drives the test, but is not a part of the expectation.

[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!");
}

I personally favour state-based testing where at all possible, though interaction based testing is often required for APIs that are designed with Tell, Don't Ask in mind, as you won't have any exposed state to verify against!

API Confusion. Mocks ain't stubs. Or are they?

The distinction between a mock and a stub in rhino mocks is muddled. Traditionally, stubs aren't meant to have expectations -- so if your test double didn't have its method called, this wouldn't directly cause the test to fail.

... However, the Rhino Mocks API is powerful, but confusing as it lets you set expectations on stubs which, to me, goes against the accepted terminology. I don't think much of the terminology, either, mind. It'd be better if the distinction was eliminated and the methods called on the test double set the role, in my opinion.

I think it has to do with what your manager.ListCount() is doing with the return value.

If it is not using it then your DAL can return anything it won't matter.

public class Manager
{
    public Manager(DAL data)
    { 
        this.data = data
    }
    public void ListCount()
    {
        data.ListCount(1); //Not doing anything with return value
        DoingSomeOtherStuff();
    }    
}

If your list count is doing something with the value you should then put assertions on what it is doing. For exemple

Assert.IsTrue(manager.SomeState == "someValue");

Have you tried using

data.AssertWasCalled(x => x.ListCount(1) = Arg.Is(EXPECTED_VALUE));
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!