views:

135

answers:

2

I'm trying to set up a stub with Rhino Mocks which returns a value based on what the parameter of the argument that is passed in.

Example:

//Arrange
var car = new Car();
var provider= MockRepository.GenerateStub<IDataProvider>();
provider.Stub(
    x => x.GetWheelsWithSize(Arg<int>.Is.Anything))
    .Return(new List<IWheel> {
                new Wheel { Size = ?, Make = Make.Michelin },
                new Wheel { Size = ?, Make = Make.Firestone }
            });

car.Provider = provider;

//Act
car.ReplaceTires();

//Assert that the right tire size was used when replacing the tires

The problem is that I want Size to be whatever was passed into the method, because I'm actually asserting later that the wheels are the right size. This is not to prove that the data provider works obviously since I stubbed it, but rather to prove that the correct size was passed in.

How can I do this?

+1  A: 

You can use the Do() functionality in order to achieve dynamic return value. For example:

[Test]
public void DynamicallyFakeReturnValue()
{
    var calculatorStub = MockRepository.GenerateStub<ICalculator>();
    calculatorStub.Stub(address => address.AddOne(Arg<int>.Is.Anything))
        .Do((Func<int, int>) (x => x - 1));

    Assert.That(calculatorStub.AddOne(1), Is.EqualTo(0));
}

In your case it will probably be:

provider.Stub(
    x => x.GetWheelsWithSize(Arg<int>.Is.Anything))
    .Do((Func<int, List<IWheel>>) (size => new List<IWheel> {
                new Wheel { Size = size, Make = Make.Michelin },
                new Wheel { Size = size, Make = Make.Firestone }
            }));
Elisha
+1  A: 

"This is not to prove that the data provider works ... but rather to prove that the correct size was passed in."

Not sure if it works that well for this particular case, but generally I've found it easiest to test these sorts of things indirectly via the stub.

Rather than checking the output of the stubbed call, explicitly specify the arguments to your stub and then verify that the return value was used as expected (regardless of the actual data returned). If it was, then you know that your stub was called correctly.

//Arrange
var wheels = new List<IWheel>();
const int wheelSize = 17;
var car = new Car();
car.WheelSize = wheelSize;
var provider= MockRepository.GenerateStub<IDataProvider>();
provider
    .Stub(x => x.GetWheelsWithSize(wheelSize))
    .Return(wheels);    
car.Provider = provider;

//Act
car.ReplaceTires();

//Assert that the right-sized wheels from the provider were
//used when replacing the tires
Assert.That(car.Wheels, Is.SameAs(wheels));

If this approach doesn't work for you in this case then you can use WhenCalled to inspect the call arguments and/or modify the return value.

provider
    .Stub(x => x.GetWheelsWithSize(Arg<int>.Is.Anything))
    .WhenCalled(x => x.ReturnValue = CreateWheelsOfSize((int) x.Arguments[0]));  

In this case CreateWheelsOfSize(int) will just create your list of wheels.

Hope this helps.

David Tchepak
@David The WhenCalled was the exact approach I ended up having to take. It allows me to make sure that I'm passing arguments through to a mock and then verifying that later. It would be awesome if there was some way to use the WhenCalled functionality without having to use the Return functionality, or perhaps just consolidating it together somehow.
Joseph
@Joseph, The easiest alternative to avoid having to use WhenCalled/Return is to make sure you control the value that is getting passed to GetWheelsWithSize (rather than using Arg<int>.Is.Anything), hence the first suggestion in my answer. If you can't get at the value it might be worth refactoring so that logic is isolated and unit-testable.
David Tchepak