Reading Code: Rhino Mocks
Join the DZone community and get the full member experience.Join For Free
I spent a bit of time recently reading through some of the Rhino Mocks to get a basic understanding of how some features work under the hood.
As well as just getting some practice at reading unfamiliar code I also wanted to know the following:How does the 'VerifyAllExpectations' extension method work?
What's the difference between the 'GenerateMock' and 'GenerateStub' methods on MockRepository?
How does the 'AssertWasNotCalled' extension method actually work?
These are some of the things I learnt from my exploration:
I'm using a Mac so I originally started out trying to read the code in TextMate with the C# plugin before eventually realising that I couldn't really tell the difference between a delegate being passed around the code and a method call so I wanted an editor that would help me out with this.
I decided to try out MonoDevelop to see if I could keep on reading the code outside my VM. Unfortunately I kept making that crash every time I tried to move between classes so back to Visual Studio it was! MonoDevelop looks like quite a nice tool but it just isn't for me at the moment.I've been playing around with an idea adapted from Michael Feathers' Working Effectively With Legacy Code by drawing out the different classes and how they interact with each other. Where I could see a grouping between classes I've been drawing that into the diagram as well.
Although these diagrams are quite simple I find them more useful than I had expected and I've started drawing more diagrams at work to help understand bits of code that I'm not very familiar with.
I realised a couple of years ago when reading one of Scott Young's posts about drawing diagrams that I seem to understand ideas more quickly if I'm able to draw them out so I should probably look to do it more frequently!The way that stubs and mocks are generated is essentially the same which I'm told is also the case with Mockito although I haven't read Mockito's code yet.
'GenerateMock' eventually calls this bit of code:
public T DynamicMock<T>(params object argumentsForConstructor)
where T : class
if (ShouldUseRemotingProxy(typeof(T), argumentsForConstructor))
return (T)RemotingMock(typeof(T), CreateDynamicRecordState);
return (T)CreateMockObject(typeof(T), CreateDynamicRecordState, new Type, argumentsForConstructor);
'GenerateStub' eventually calls this bit of code:
public object Stub(Type type, params object argumentsForConstructor)
CreateMockState createStub = mockedObject => new StubRecordMockState(mockedObject, this);
if (ShouldUseRemotingProxy(type, argumentsForConstructor))
return RemotingMock(type, createStub);
return CreateMockObject(type, createStub, new Type, argumentsForConstructor);
The main difference is that when the 'Verify' method is called on stubs (which would call the 'StubReplayMockState' class) we don't do anything whereas with mocks a check is done to ensure that all the expectations setup in the test are met.
I found it quite interesting that the new 'Arrange-Act-Assert' style syntax has been written to make use of the older 'Record-Replay' syntax which I guess is quite a nice metaphor for the two states that you use the framework.
I haven't looked at the Moq code yet but it would be interesting to see how the code for that differs as it was built from the ground up with the 'Arrange-Act-Assert' syntax.
The 'AssertWasNotCalled' method works fairly similarly to how I had imagined at a high level in that it goes and gets all the expectations for the mock for that method call and then checks that they aren't called although I found the implementation of that first bit quite interesting.
private static ExpectationVerificationInformation GetExpectationsToVerify<T>(T mock, Action<T> action, Action<IMethodOptions<object>> setupConstraints)
var mockToRecordExpectation = (T)mocks.DynamicMock(FindAppropriteType(mockedObject), mockedObject.ConstructorArguments);
The code actually creates a mock in order to record the expectation that we are checking does not happen before it goes on to check which methods were called against that method. We therefore need to ensure that any calls to 'AssertWasNotCalled' are made after the call to the system under test otherwise it will always return true which may not be accurate.I didn't realise quite how much code there is in Rhino Mocks and I've only read a very small part of it. A few of the interesting parts of the code seem to be making calls to Castle DynamicProxy which is being used to do the intercepting of method calls.
I'm never sure what the best way to approach a new code base is but this time I had a couple of starting points that I wanted to investigate and starting from those points seemed to work out quite well. I still find that I struggle to know when to stop digging down into how specific code works and when to just have a general understanding of that bit and move on to the next bit of code. I often find that I click all the way through to deeper methods and then I can't remember why I did it in the first place.
Published at DZone with permission of Mark Needham, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.