silver
silver

Reputation: 1703

Rhino mocks stubbing twice the same function doesn't work as expected

I've started to work with Rhino recently and encountered a very unexpected behavior that I couldn't overcome.

The issue is that I have an infrastructure of my stubs and in one of my tests I needed to change one of the predefined stubs (in my infrastructure) to return a different value then the default one.

I've reproduce the issue in the following code:

[TestFixture]
public class UnitTest1
{
    private IWorker _worker;

    [SetUp]
    void Setup()
    {
        _worker = MockRepository.GenerateStub<IWorker>();
        _worker.Stub(w=>w.DoWork()).Return(0);
    }

    [Test]
    public void DoWork_StubbingFunctionTwice_CallingTheLastStub()
    {
        int expected = 1;
        _worker.Stub(w => w.DoWork()).Return(expected);
        int actual =_worker.DoWork();
        Assert.AreEqual(expected, actual);
    }

}

public interface IWorker
{
    int DoWork();
}

someone knows why the Rhino stubs are behaving this way and more important how can I solve it in the cleanest way?

Upvotes: 5

Views: 1651

Answers (1)

Old Fox
Old Fox

Reputation: 8725

When you specify a behavior on a fake object in RhinoMocks without any constraint(RepeatOnce and etc..) the behavior will stay and you won't be able to override it.(actually option 1 shows how you can...)

In your case you specify a specific behavior in the Setup method:

_worker.Stub(w=>w.DoWork()).Return(0);

The above line will execute before _worker.Stub(w => w.DoWork()).Return(expected);.

The best practice for SetUp / TestInitialize attributes is to group inside them only settings which you want to apply in all test methods.

By default any method with a return value returns the default(T) so you can remove _worker.Stub(w=>w.DoWork()).Return(0); and then any thing will work.

If your real case is more complex:

Option1: clear the mock

// clear expectations, an enum defines which
_worker.BackToRecord(BackToRecordOptions.All);

// go to replay again.
_worker.Replay();

Option2: limit the behavior

_worker.Stub(w=>w.DoWork()).Return(0).Repeat.Once(); // or the max time you need...

and then add a loop inside the test method:

for(...; i < num of time; ...)
    _worker.DoWork();

Option3: create a new fake and CUT(class under test)

Upvotes: 4

Related Questions