Rhino.Mocks: method calls recorder (a.k.a. test spy)
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开发者_JS百科 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):
- Advanced mocking: anonymous test spy
- Perhaps using Windsor Castle's interceptors?
// 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
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 :)
精彩评论