Rhino Mocks - Stub .Expect vs .AssertWasCalled

前端 未结 3 2171
独厮守ぢ
独厮守ぢ 2020-12-07 23:00

OK, I know there has been a lot of confusion over the new AAA syntax in Rhino Mocks, but I have to be honest, from what I have seen so far, I like. It reads better, and sa

相关标签:
3条回答
  • 2020-12-07 23:13

    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.

    0 讨论(0)
  • 2020-12-07 23:18

    Have you tried using

    data.AssertWasCalled(x => x.ListCount(1) = Arg.Is(EXPECTED_VALUE));
    
    0 讨论(0)
  • 2020-12-07 23:29

    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");
    
    0 讨论(0)
提交回复
热议问题