Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reusing a verified Mock

Tags:

c#

rhino-mocks

I am doing ordered expectations in rhino mocks as described by ayende in this post. My code looks something like this:

using (_mocks.Ordered())
  {
    Expect.Call(() => _myMock.CallA());
    Expect.Call(() => _myMock.CallB(40));
    Expect.Call(() => _myMock.CallA());
  }
  _mocks.ReplayAll();
  _myObjectUnderTest.DoStuff();
  _mocks.VerifyAll();

After this I would like to add more expectations and test more of my object's methods. I want to do this because I have some basic test methods that do some setup on my test object, and I do not want to have to retest that functionality, so I just call the earlier test method. If I try and add more expectations after VerifyAll() I get an exception: "This action is invalid when the mock object is in verified state."

Part of my problem is that I don't really understand what all of the replay/verify stuff is doing, I just copied code. I am using strict mocks, so any setup code must have matching expectations or it fails. I do not want to duplicate the expectations for my setup code.

Is there a way to reset the mock to be ready to start over in some way?

like image 468
captncraig Avatar asked Oct 25 '10 22:10

captncraig


2 Answers

Short answer: no. Now on to the long answer.

What the replay and verify stuff does is this. Before you call ReplayAll, you are telling Rhino what you expect the methods are going to do. You in a sense are recording calls to the mock objects you've created.

After you've recorded the method calls, you call ReplayAll telling Rhino you're now going to do 'something' that should execute the methods as recorded.

Last, you call VerifyAll asking Rhino to verify whether the methods were actually called as you've recorded them.

Now on to why you really should not want to re-use the mocks. With unit testing/TDD, your unit test should test as little as possible. This is to keep your unit tests simple and transparent. The whole idea of unit testing is that many many many small tests as a whole test the entire system.

For a very good presentation on TDD explaining this and other subjects, see http://www.infoq.com/presentations/integration-tests-scam.

P.S.: One small detail: As long as the methods don't return a result, you can write:

using (_mocks.Ordered())
{
    Expect.Call(() => _myMock.CallA());
    Expect.Call(() => _myMock.CallB(40));
    Expect.Call(() => _myMock.CallA());
}

as:

using (_mocks.Ordered())
{
    _myMock.CallA();
    _myMock.CallB(40);
    _myMock.CallA());
}

(at least with the latest version of Rhino)

like image 178
Pieter van Ginkel Avatar answered Nov 07 '22 12:11

Pieter van Ginkel


Short answer: yes

Longer answer: Try the following

    [Test]
    public void RhinoMock_PerformMultipleChecks()
    {
        var myMock = MockRepository.GenerateDynamicMockWithRemoting<IComparable>();

        // first round of checks
        myMock.Expect(x => x.CompareTo("123")).Return(1);
        myMock.Expect(x => x.CompareTo("-12")).Return(-1);
        Assert.AreEqual(1, myMock.CompareTo("123"));
        Assert.AreEqual(-1, myMock.CompareTo("-12"));
        myMock.VerifyAllExpectations();

        // reset
        myMock.BackToRecord();
        myMock.Replay();

        // next round of checks
        myMock.Expect(x => x.CompareTo(1.23)).Return(1);
        myMock.Expect(x => x.CompareTo(-12)).Return(-1);
        Assert.AreEqual(1, myMock.CompareTo(1.23));
        Assert.AreEqual(-1, myMock.CompareTo(-12));
        myMock.VerifyAllExpectations();

        // reset
        myMock.BackToRecord();
        myMock.Replay();

        // final round of checks
        myMock.Expect(x => x.CompareTo(1.23m)).Return(1);
        myMock.Expect(x => x.CompareTo(-12m)).Return(-111);
        Assert.AreEqual(1, myMock.CompareTo(1.23m));
        Assert.AreEqual(-111, myMock.CompareTo(-12m));
        myMock.VerifyAllExpectations();
    }
like image 42
brewmanz Avatar answered Nov 07 '22 12:11

brewmanz