Want to show your appreciation? Please to my charity.

Saturday, June 27, 2009

Rhino.Mocks Ordered Expectations Enhanced API for AAA

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.");

        }
    }

No comments:

Post a Comment