In my last post, I proposed a way, an affordable way, to have Rhino.Mocks support ordered expectations in AAA syntax. I introduced one extension method Before. Actually, with that ground work, we can quickly add more ordering related extension methods. Let's take a look at same asserts in the test case to see what are possible.
mockBefore.AssertWasCalled(b => b.MethodBefore())
.Before(mockAfter.AssertWasCalled(a => a.MethodAfter()));
mockAfter.AssertWasCalled(a => a.MethodAfter())
.After(mockBefore.AssertWasCalled(b => b.MethodBefore()));
mockBefore.AssertWasCalled(b => b.MethodBefore()).First()
.Before(mockAfter.AssertWasCalled(a => a.MethodAfter()).First())
.Before(mockBefore.AssertWasCalled(b => b.MethodBefore()).Last());
mockAfter.AssertWasCalled(a => a.MethodAfter()).Last()
.After(mockBefore.AssertWasCalled(b => b.MethodBefore()).Last())
.After(mockAfter.AssertWasCalled(a=>a.MethodAfter()).First());
With the enhanced API, you can
- Chain multiple Before and After calls, even mix the Before and After.
- When a method is called multiple times, you can specify if the expectation should apply the first call or last call.
And below are how they are implemented.
/// <summary> /// Assert that all calls specified by <paramref name="beforeCalls"/> /// occurred before all calls specified by <paramref name="afterCalls"/> /// </summary> /// <param name="beforeCalls"> /// Calls that happens before <paramref name="afterCalls"/> /// </param> /// <param name="afterCalls"> /// Calls that happens after <paramref name="beforeCalls"/> /// </param> public static IList<CallRecord> Before(this IList<CallRecord> beforeCalls, IList<CallRecord> afterCalls) { Ordered(Last(beforeCalls), First(afterCalls)); return afterCalls; } /// <summary> /// Assert that all calls specified by <paramref name="afterCalls"/> /// occurred after all calls specified by <paramref name="beforeCalls"/> /// </summary> /// <param name="afterCalls"> /// Calls that happens after <paramref name="beforeCalls"/> /// </param> /// <param name="beforeCalls"> /// Calls that happens before <paramref name="afterCalls"/> /// </param> public static IList<CallRecord> After(this IList<CallRecord> afterCalls, IList<CallRecord> beforeCalls) { Ordered(Last(beforeCalls), First(afterCalls)); return beforeCalls; } /// <summary> /// Assert that the call specified by <paramref name="before"/> /// occurred before the call specified by <paramref name="after"/> /// </summary> /// <param name="before"> /// Call that occurred before <paramref name="after"/> /// </param> /// <param name="after"> /// Call that occurred after <paramref name="before"/> /// </param> public static CallRecord Before(this CallRecord before, CallRecord after) { Ordered(before, after); return after; } /// <summary> /// Assert that the call specified by <paramref name="after"/> /// occurred after the call specified by <paramref name="before"/> /// </summary> /// <param name="after"> /// Call that occurred after <paramref name="before"/> /// </param> /// <param name="before"> /// Call that occurred before <paramref name="after"/> /// </param> public static CallRecord After(this CallRecord after, CallRecord before) { Ordered(before, after); return before; } /// <summary> /// Returns the last executed call in the <paramref name="callRecords"/>. /// </summary> /// <param name="callRecords"> /// A list of call records ordered by the time they were executed. /// </param> /// <returns>The last call executed in <paramref name="callRecords"/></returns> public static CallRecord Last(this IList<CallRecord> callRecords) { return callRecords[callRecords.Count - 1]; } /// <summary> /// Returns the first executed call in the <paramref name="callRecords"/>. /// </summary> /// <param name="callRecords"> /// A list of call records ordered by the time they were executed. /// </param> /// <returns>The first call executed in <paramref name="callRecords"/></returns> public static CallRecord First(this IList<CallRecord> callRecords) { return callRecords[0]; } private static void Ordered(CallRecord before, CallRecord after) { if (before.Sequence > after.Sequence) { throw new ExpectationViolationException( "Expected that call " + before.Method + " occurs before call " + after.Method + ", but the expectation is not satisfied."); } }