Capturing Rhino Mocks arguments in C# 4.0


As a quick review, a test fixture has inputs and outputs.  We set up our test fixture by configuring inputs.  We observe the results through the fixture’s outputs.

Inputs and outputs can be grouped into direct and indirect variants.  Direct inputs include:

  • Constructor arguments
  • Method arguments
  • Property/field values

Indirect inputs are things we can’t directly set on our fixture.  An example would be a ShippingCalculatorService, that returns a shipping cost.  An order processor might use this service to calculate the full cost of an order.  However, we don’t directly set this shipping cost through the direct use of our order processor.  Instead, the shipping cost is an indirect input to our method through this shipping calculator.

On the other side of the coin are direct outputs, which include:

  • Return values
  • Mutated inputs
  • Mutated fixture

Often, we just look at the return value of a method for the direct output.  But we might also look at one of the inputs, which might have mutated as the result of an operation.  We also have indirect outputs, which again are services whose methods are void.

If we properly follow Command-Query Separation, we can group our Rhino Mock usage into only two buckets:

  • Stubbing indirect inputs
  • Capturing indirect outputs

The first case is easy.  The second one can get ugly, as it requires the use of rather funky looking call.  Let’s say we have an order processor that reserves shipping spots through a service:

public interface IShippingReservationService
{
    void Reserve(int orderId, decimal totalWeight);
}

If we want to capture ALL arguments made and want to assert things, we must do something like:

IList<object[]> argsMade = shipper.GetArgumentsForCallsMadeOn(
    s => s.Reserve(0, 0m), 
    opt => opt.IgnoreArguments());

argsMade[0][0].ShouldEqual(batch1.Id);

Not too pretty.  I have to make sure I use the “IgnoreArguments” configuration option, so that I get all calls.  Next, I get an IList<object[]>, which is basically a jagged array of objects.  Everything is an object, so I have to cast if I want to do any special assertions.

But if we’re in C# 4.0, we can do better.

Capturing one argument-methods

I’d really like to capture all the arguments made as a single list of items. First, let’s look at the simple case where I have an indirect output with only ONE argument:

public interface IOrderProcessor
{
    void Process(OrderBatch batch);
}

In that case, I only want to capture the arguments made as a list of OrderBatch.  No real need to wrap that with anything else at this point.  To do this, I first set up my objects as I normally would with Rhino Mocks:

var processor = Stub<IOrderProcessor>();
var shipper = Stub<IShippingReservationService>();

var batchProcessor = new OrderBatchProcessor(processor, shipper);

The Stub method merely wraps MockRepository.GenerateStub().  From here, I want to then capture the arguments made.  In previous versions, I would do this by passing in a closure for the Do() method of Rhino Mocks.  I can extend this to a general case:

IList<OrderBatch> args = processor
    .Capture()
    .Args<OrderBatch>((p, batch) => p.Process(batch));

batchProcessor.ProcessBatches(new[]
{
    batch1, batch2, batch3
});

args.Count().ShouldEqual(3);
args.First().ShouldEqual(batch2);

I capture the arguments made as a list of OrderBatch, then call the ProcessBatches as normal.  I have some logic where express batches are processed first, which is why I assert that “batch2” came first.

The CaptureMethod is an extension method that begins a chain for me to start capturing arguments:

public static class MockExtensions
{
    public static CaptureExpression<T> Capture<T>(this T stub) 
        where T : class
    {
        return new CaptureExpression<T>(stub);
    }
}

I have to return a CaptureExpression as a trick so that I don’t have to specify the stub’s type in my test.  My CaptureExpression then lets me capture the args:

public class CaptureExpression<T>
    where T : class
{
    private readonly T _stub;

    public CaptureExpression(T stub)
    {
        _stub = stub;
    }

    public IList<U> Args<U>(Action<T, U> methodExpression)
    {
        var argsCaptured = new List<U>();

        Action<U> captureArg = argsCaptured.Add;
        Action<T> stubArg = stub => methodExpression(stub, default(U));

        _stub.Stub(stubArg).IgnoreArguments().Do(captureArg);

        return argsCaptured;
    }

In the Args method, I accept an expression detailing the method I want to call.  I create a list of the arguments, which is where I’ll stash them as they come in.  In the next couple of lines, I build the delegates that Rhino Mocks uses to both stub a method, and provide a stand-in callback.

Finally, I use the Stub() and Do() methods from Rhino Mocks to provide a replacement closure for calling the original method.  When the stubbed method is called, Rhino Mocks passes control to my CaptureArg method.  This method is a closure that adds the method argument to the “argsCaptured” list.

Initially, the list returned is empty.  But as the stub is used in the fixture, this list will be populated with the items used.

That’s the easy case of a single argument, let’s look at multiple arguments.

Capturing multiple arguments with tuples

I’d also like group the arguments made from each call into a single object, instead of just an array that I have to then poke around in.  In earlier versions of C#, I would need to craft an object to hold these values.  In C# 4.0, I have the Tuple classes.

I’ll follow the same pattern here as the method above, except this time use the Tuple class to group the method arguments together:

public IList<Tuple<U1, U2>> Args<U1, U2>(Action<T, U1, U2> methodExpression)
{
    var argsCaptured = new List<Tuple<U1, U2>>();

    Action<U1, U2> captureArg = (u1, u2) => argsCaptured.Add(Tuple.Create(u1, u2));
    Action<T> stubArg = stub => methodExpression(stub, default(U1), default(U2));

    _stub.Stub(stubArg).IgnoreArguments().Do(captureArg);

    return argsCaptured;
}

I return a Tuple<U1, U2>, which are the types of the method parameters of the stubbed method, but now just grouped together in a strongly-typed bucket.  I can now create strongly-typed assertions about my indirect outputs:

var processor = Stub<IOrderProcessor>();
var shipper = Stub<IShippingReservationService>();

var args = shipper
    .Capture()
    .Args<int, decimal>((s, orderId, weight) => s.Reserve(orderId, weight));

var batchProcessor = new OrderBatchProcessor(processor, shipper);

batchProcessor.ProcessBatches(new[]
{
    batch1, batch2
});

args.Count.ShouldEqual(2);
args[0].Item1.ShouldEqual(batch1.Id);
args[0].Item2.ShouldEqual(batch1.TotalWeight);
args[1].Item1.ShouldEqual(batch2.Id);
args[1].Item2.ShouldEqual(batch2.TotalWeight);

Additionally, because I don’t have to guess at the number of arguments made, the Tuple returned is linked to the number of arguments to the stubbed method.  This provides a much stronger link between the arguments I capture and the method being stubbed.

From here, it’s trivial to extend this approach to as many arguments as I need.  And as long as I stick to CQS, and my methods either do something or answer a question, these are the only mocking requirements I’ll need.  As always, you can find this example on my github.

Translating my Git workflow with local branches to Mercurial