Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ordering method return values with Rhino-Mock stubs

I've started experimenting with Rhino-Mocks (3.6) while reading Roy Osherove's The Art of Unit Testing. He has an example that demonstrates that a mocked method can be scripted to return different results when called twice with the same parameter:

   [Test]
    public void ReturnResultsFromMock()
    {
        MockRepository repository = new MockRepository();
        IGetRestuls resultGetter = repository.DynamicMock<IGetRestuls>();
        using(repository.Record())
        {
            resultGetter.GetSomeNumber("a");
            LastCall.Return(1);

            resultGetter.GetSomeNumber("a");
            LastCall.Return(2);

            resultGetter.GetSomeNumber("b");
            LastCall.Return(3);

        }

        int result = resultGetter.GetSomeNumber("b");
        Assert.AreEqual(3, result);

        int result2 = resultGetter.GetSomeNumber("a");
        Assert.AreEqual(1, result2);

        int result3 = resultGetter.GetSomeNumber("a");
        Assert.AreEqual(2, result3);
    }

This works fine. But when I try the same thing with a Stub, and a method that accepts and returns a string, I am not able to generate the second return value:

    [Test]
    public void StubMethodWithStringParameter_ScriptTwoResponses_SameResponseReceived()
    {
        MockRepository mocks = new MockRepository();
        IMessageProvider stub = mocks.Stub<IMessageProvider>();

        using (mocks.Record())
        {
            stub.GetMessageForValue("a");
            LastCall.Return("First call");
            stub.GetMessageForValue("a");
            LastCall.Return("Second call");
        }

        Assert.AreEqual("First call", stub.GetMessageForValue("a"));
        Assert.AreEqual("Second call", stub.GetMessageForValue("a"));
    }
}

public interface IMessageProvider
{
    string GetMessage();
    string GetMessageForValue(string value);
}

This test is failing, because "First Call" is received for both calls. I've tried several wrinkles of syntax (Using mocks.Ordered(), SetResult, Expect etc.), but am still unable to get the second result to appear.

Am I doing something wrong, or is this a limitation with Rhino-Mocks? I've checked this blog post, but the suggested syntax did not resolve my issue.

like image 592
Dan Solovay Avatar asked Apr 10 '11 03:04

Dan Solovay


2 Answers

The bit you're missing is to tell the stub that the first value should only be returned once:

...
using (mocks.Record())
{
    stub.GetMessageForValue("a");
    LastCall.Return("First call").Repeat.Once();
    stub.GetMessageForValue("a");
    LastCall.Return("Second call");
}

Of course your "Second call" really means "Second-or-subsequent call" unless you impose other restrictions with Repeat.

You might also consider using the newer Arrange, Act, Assert (AAA) syntax RhinoMocks now offers:

[Test]
public void StubMethodWithStringParameter_ScriptTwoResponses_SameResponseReceived()
{
    IMessageProvider stub = MockRepository.GenerateStub<IMessageProvider>();

    stub.Expect(mp => mp.GetMessageForValue("a"))
        .Return("First call")
        .Repeat.Once();
    stub.Expect(mp => mp.GetMessageForValue("a"))
        .Return("Second call");

    Assert.AreEqual("First call", stub.GetMessageForValue("a"));
    Assert.AreEqual("Second call", stub.GetMessageForValue("a"));
}

It's a little more concise and generally saves you from having to worry about the record-playback-assert state of the stub. Derick Bailey wrote an article about using Repeat on Los Techies. It also happens to use the AAA syntax).

like image 199
Mr. Putty Avatar answered Nov 09 '22 06:11

Mr. Putty


I think if you are working with stubs, using Expect does not fit as you do not want an expectation but a replacement for your dependency.

So I believe if you use the stub syntax it makes more sense:

stub.Stub.(s=>s.GetMessageForValue("a"))
                            .Return("First call").Repeat.Once(); 

stub.Stub.(s=>s.GetMessageForValue("a"))
                            .Return("Second call").Repeat.Any;
like image 44
pencilCake Avatar answered Nov 09 '22 05:11

pencilCake