Beautiful (nontrivial) Code - Rhino Mocks 3.5's AssertWasCalled

time to read 3 min | 446 words

Beautiful code is not something that is easy to define. I think of this as something that is extremely elegant, that solve a hard problem in a way that isn't brute force. I think that the way Rhino Mocks implements the AssertWasCalled functionality is elegant, and I would like to point it out.

I know of at least one contributor to Rhino Mocks who consider that piece of code scary, by the way, so it is not cut & dry.

Here is the actual method call:

public static void AssertWasCalled<T>(this T mock, Action<T> action, 
	Action<IMethodOptions<object>> setupConstraints)
{
	ExpectationVerificationInformation verificationInformation = 
		GetExpectationsToVerify(mock, action, setupConstraints);

	foreach (var args in verificationInformation.ArgumentsForAllCalls)
	{
		if (verificationInformation.Expected.IsExpected(args))
		{
			verificationInformation.Expected.AddActualCall();
		}
	}
	if (verificationInformation.Expected.ExpectationSatisfied)
		return;
	throw new ExpectationViolationException(
		verificationInformation.Expected.BuildVerificationFailureMessage());
}

We will get the GetExpectaionsToVerify in a bit, but broadly, it gets the expectation that should have been called and then it execute the same logic that it would have in the Record/Replay model. In fact, it is an exact reversal of the Record/Replay model. Now we record all the actual calls, and then we create an expectation and try to match it against the actual calls that were made against the actual object.

Of even more interest is how we get the expectation that we are verifying:

private static ExpectationVerificationInformation GetExpectationsToVerify<T>(T mock, Action<T> action,
		Action<IMethodOptions<object>> setupConstraints)
{
	IMockedObject mockedObject = MockRepository.GetMockedObject(mock);
	MockRepository mocks = mockedObject.Repository;

	if (mocks.IsInReplayMode(mockedObject) == false)
	{
		throw new InvalidOperationException(
			"Cannot assert on an object that is not in replay mode." +
			" Did you forget to call ReplayAll() ?");
	}

	var mockToRecordExpectation = (T)mocks.DynamicMock(
		mockedObject.ImplementedTypes[0], 
		mockedObject.ConstructorArguments);

	action(mockToRecordExpectation);

	AssertExactlySingleExpectaton(mocks, mockToRecordExpectation);

	IMethodOptions<object> lastMethodCall = mocks.LastMethodCall<object>(mockToRecordExpectation);
	lastMethodCall.TentativeReturn();
	if (setupConstraints != null)
	{
		setupConstraints(lastMethodCall);
	}
	ExpectationsList expectationsToVerify = 
		mocks.Replayer.GetAllExpectationsForProxy(mockToRecordExpectation);
	if (expectationsToVerify.Count == 0)
	{
		throw new InvalidOperationException(
			"The expectation was removed from the waiting expectations list,"+
			" did you call Repeat.Any() ? This is not supported in AssertWasCalled()");
	}
	IExpectation expected = expectationsToVerify[0];
	ICollection<object[]> argumentsForAllCalls = mockedObject.GetCallArgumentsFor(expected.Method);
	return new ExpectationVerificationInformation
			{
				ArgumentsForAllCalls = new List<object[]>(argumentsForAllCalls),
				Expected = expected
			};
}

This is even more interesting. We create a new mocked object, and execute it in record mode against the expectation that we wish to verify. We gather this expectation and extract that from the newly created mock object, to pass it to the AssertWasCalled method, where we verify that against the actual calls made against the object.

What I find elegant in the whole thing is not just the reversal of the record / replay model, it is the use of Rhino Mocks to extend Rhino Mocks.