RhinoMocks - mocking a method whose return value c

2019-03-23 02:09发布

问题:

I'm looking to find out how I can mock a method that returns a different value the second time it is called to the first time. For example, something like this:

public interface IApplicationLifetime
{
    int SecondsSinceStarted {get;}
}

[Test]
public void Expected_mock_behaviour()
{
    IApplicationLifetime mock = MockRepository.GenerateMock<IApplicationLifetime>();

    mock.Expect(m=>m.SecondsSinceStarted).Return(1).Repeat.Once();
    mock.Expect(m=>m.SecondsSinceStarted).Return(2).Repeat.Once();

    Assert.AreEqual(1, mock.SecondsSinceStarted);
    Assert.AreEqual(2, mock.SecondsSinceStarted);
}

Is there anything that makes this possible? Besides implementing a sub for the getter that implements a state machine?

Cheers fellas,

Alex

回答1:

You can intercept return values with .WhenCalled method. Note that you still need to provide value via .Return method, however Rhino will simply ignore it if ReturnValue is altered from method invocation:

int invocationsCounter = 1;
const int IgnoredReturnValue = 10;
mock.Expect(m => m.SecondsSinceLifetime)
    .WhenCalled(mi => mi.ReturnValue = invocationsCounter++)
    .Return(IgnoredReturnValue);

Assert.That(mock.SecondsSinceLifetime, Is.EqualTo(1));
Assert.That(mock.SecondsSinceLifetime, Is.EqualTo(2));

Edit:

Digging around a bit more, it seems that .Repeat.Once() does indeed work in this case and can be used to achieve same result:

mock.Expect(m => m.SecondsSinceStarted).Return(1).Repeat.Once();
mock.Expect(m => m.SecondsSinceStarted).Return(2).Repeat.Once();
mock.Expect(m => m.SecondsSinceStarted).Return(3).Repeat.Once();

Will return 1, 2, 3 on consecutive calls.



回答2:

Simply use

mock.Expect(m=>m.SecondsSinceStarted).Return(1).Repeat.Once();
mock.Expect(m=>m.SecondsSinceStarted).Return(2).Repeat.Once();

This will return 1 during first call, and 2 during second call. At least on RhinoMocks 3.6.0.0



回答3:

Is time the determining factor in what the method returns? If so, I would try to abstract out the time passage so you have direct control over it in your tests.

Something like an interface called ITimeProvider with a member called GetElapsedTime() and then create a default implementation to use throughout your application.

Then when you are testing, pass in a mocked ITimeProvider so you control what is perceived by your application to be time passed.