I've been working with Rhino Mocks for a couple of days now and I'm duly impressed. Aside from being generally useful, the Rhino Mocks syntax is mostly natural and some very clever design hacks are used to make it work the way you'd expect it to. (In case you don't know what mocking frameworks are, the subject has been tackled ad nauseam. Just take your pick.)
There is one caveat that is not immediately visible in the Record-Playback syntax, though:
internal interface IFoo { int Bar(); }[Test] [ExpectedException( typeof( InvalidOperationException ), "Type 'System.Object' doesn't match the return type " + "'System.Int32' for method 'IFoo.Bar();'" )] public void TestRecordSyntax_ReturnTypeMismatchBehavior() { MockRepository mocks = new MockRepository(); IFoo mock = mocks.CreateMock<IFoo>(); using ( mocks.Record() ) Expect.Call( mock.Bar() ).Return( new object() ); }
internal interface IFoo { int Bar(); }
[Test] [ExpectedException( typeof( InvalidOperationException ), "Type 'System.Object' doesn't match the return type " + "'System.Int32' for method 'IFoo.Bar();'" )] public void TestRecordSyntax_ReturnTypeMismatchBehavior() { MockRepository mocks = new MockRepository(); IFoo mock = mocks.CreateMock<IFoo>(); using ( mocks.Record() ) Expect.Call( mock.Bar() ).Return( new object() ); }
This simple test merely returns an incorrectly typed return value for the IFoo.Bar method, so with the ExpectedException in place you'd expect it to succeed, but you're in for a surprise:
[failure] RecordPlaybackTests.TestSetup.ConsistentReturnTypeMismatchBehaviorTestCase 'RecordPlaybackTests.TestSetup.ConsistentReturnTypeMismatchBehavior'failed: Exception of type 'MbUnit.Core.Exceptions.ExceptionExpectedMessageMismatchException' was thrown. Expected exception message: "Type 'System.Object' doesn't match the return type 'System.Int32' for method 'IFoo.Bar();'", got "Previous method 'IFoo.Bar();' require a return value or an exception to throw.".
To understand this, consider the following flow:
This is in fact how I first encountered this behavior, however there are several scenarios where this can happen. One example: setting up a return value that throws an exception on construction, possibly due to invalid arguments, causes the same behavior thereby masking the true cause of the error.
An alternative syntax suggested by Ayende (author of Rhino Mocks) is:
With.Mocks( delegate { Expect.Call( mock.Bar() ).Return( new object() ); } );
Aside from the esthetical aspect (i.e. butt-ugly), this syntax introduces a minor issue: you cannot Edit-and-Continue methods with anonymous delegates. This may not be a big deal for test code but it's worth noting.
All in all I don't consider this a big issue, but it can bite and should therefore be understood and documented. This post will be reflected in the Rhino Mocks wiki shortly and will hopefully save someone a little grief in the future...
Remember Me
a@href@title, b, blockquote@cite, em, i, strike, strong, sub, super, u
© Copyright 2008 Tomer Gabel Based on theme design by Bryan Bell | | Powered by newtelligence dasBlog 2.0.7226.0 |  Page rendered at Sunday, October 12, 2008 3:05:49 PM (Jerusalem Standard Time, UTC+02:00)