views:

77

answers:

2

I have a piece of logic I want to test and it uses dependency injected interface with one (or more) void methods, example:

interface IMyService
{
    void MethodA (MyComplexObject arg1, int arg2);
}

What I would want is to create a stub for this IMyService that would just record the method invocations of MethodA and I would later be able to access it as a list, something like:

MyComplexObject actualParameter = serviceRecorder
    .GetMethodRecordings("MethodA").GetRecord(10).GetInputParameter(0);

I need this to examine the contents of such a parameter for a certain invocation and make assertions on it. I know there are other was of doing it (like setting expectation calls with constraints), but this seems much easier to write for cases when you have a lot of invocations and you want to make assertions on the 51th one only, for example.

So is there some sort of mechanism in Rhino.Mocks for this or am I left to my own devices (writing dummy IMyService implementation with recording capabilities)?

NOTE: (I'm aware this could lead to tests being fragile and I'm aware of the consequences).

UPDATE: here's what I found so far (thanks in part to Mark's help in naming this pattern as Test Spy):

+2  A: 

Take a look at the Arrange-Act-Assert (AAA) syntax of Rhino Mocks.

In overall, the Record-Replay syntax is obsolete. It was fantastic when it was invented, but with the advent of lambda expressions we got something even better.

Rhino Mocks 4 is probably not going to support Record-Replay, but instead relies on lambda expressions, and so does Moq.

Finally, a Test Double that records invocations for later inspection is called a Test Spy - see xUnit Test Patterns for more information :)

Mark Seemann
Mark, I'm already using AAA syntax, but I suspect AAA vs. record-replay is not an issue here - the underlying mocking logic still has the ability to intercept calls.As for Test Spy: thanks for pointing this out - I haven't yet reached that part of the book :)
Igor Brejc
+1 for mentioning both the happy departure of Record-Replay and the excellent Moq library!
TrueWill
+2  A: 
// arrange
var myServiceStub = MockRepository.GenerateStub<IMyService>();
var myComplexObj = new MyComplexObject 
{
    SomeProp = "something",
    SomeOtherProp = "something else"
};

// act
myServiceStub.MethodA(myComplexObj, 10);

// assert
myServiceStub.AssertWasCalled(
    x => x.MethodA(
        Arg<MyComplexObject>.Matches(
            arg1 => arg1.SomeProp == "something" &&
                    arg1.SomeOtherProp == "something else"
        ), 
        Arg<int>.Is.Equal(10)
    )
);

Remark: Don't forget to make the interface public or Rhino Mocks won't be able to create a proxy.


UPDATE:

Sorry I didn't read your question carefully. Here's how to get the desired behavior:

var args = myServiceStub.GetArgumentsForCallsMadeOn(
    x => x.MethodA(null, default(int)),
    x => x.IgnoreArguments()
);

var theComplexObjectPassedAtThe51thCall = (MyComlexObject)args[50][0];
// TODO: assert something on this object
Darin Dimitrov
Darin thanks, but this is what I was trying to avoid: complex inline assertion logic. Anyway, how would you do this kind of assertion on a 51st invocation, for example? It can be done, but then the test code becomes bloated. I want to separate the recording out of the actual test code.
Igor Brejc
@Igor, see my update.
Darin Dimitrov
Cool, this is exactly what I was looking for :). Thanks!
Igor Brejc