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

        }
    }

Rhino.Mocks Ordered Expectations for AAA Syntax

There was a question posted to the Google Group about how to make ordered expectations using AAA syntax in Rhino.Mocks. As people being increasingly aware of over specification using the record/reply model. Arrange-Action-Assert model is getting adopted by more and more developers. In the question, Alex was asking if is a way to make the ordered expectations using AAA syntax instead of the workaround he used below which is, IMHO, quite tedious to write and understand.

        public void ViewTitleSetBeforeShownInWorkspace()
        {
            //arrange
            var mockView = MockRepository.GenerateMock<IView>();
            bool viewTitleSet = false;
            mockView.Stub(x => x.Title = Arg<string>.Is.Anything)
                .WhenCalled(a => { viewTitleSet = true; });
            mockView.Stub(x => x.ShowInWorkspace("MyWorkspace"))
                .WhenCalled(a => { Assert.IsTrue(viewTitleSet, 
                    "View title should have been set first"); });

            //act
            var target = new Presenter(mockView);
            target.Initialize();

            //assert
            mockView.AssertWasCalled(x => x.ShowInWorkspace("MyWorkspace"));
        }

I agree with Ayende Rahien that ordered expectation is rare. But it does happen and I wish there is a way to do it when I need it. I again agreed that duplicating full ordering support from record/reply into AAA is too complex than worth. It would be not only over killed but also easily abused.

But, maybe there is a simpler way to the goal. All I need is to ensure one method should have been called before another, I want a way to verify this as easy as AssertWasCalled.

How about something like below:

            mockBefore.AssertWasCalled(b => b.MethodBefore())
                .Before(mockAfter.AssertWasCalled(a => a.MethodAfter()));

I loves to use open source tools because if nobody doing it then I do it myself. I checked out the Rhino.Mocks source code from Subversion repository. It turned out to be quite straightforward to make it work. Thanks to Ayende for the nice design. Going around the code and making changes were very easy. I was a bit afraid of scratching the crystal when making those changes. Ayende, please forgive me if I did.

Rhino.Mocks does record each call so that it can later use the information to verify the expectations. But the current design only records call parameters. I changed it to record a newly introduced CallRecord object.

    public class CallRecord
    {
        private static long sequencer = long.MinValue;

        internal CallRecord()
        {
            Sequence = Interlocked.Increment(ref sequencer);
        }
        internal object[] Arguments { get; set; }
        internal long Sequence { get; private set; }
        internal MethodInfo Method { get; set; }
    }

The key in this object is the sequencer. Every time a new CallRecord is created, the sequencer was increased in a thread safe manner. And the current sequence is recorded with the call. So each CallRecord object in the system has a unique Sequence value that can be used to determine the time order of the calls at later time.

The Arguments property is used by the original Rhino.Mocks to check expectations. Having Method property here was due to my laziness. There should be a better way to handle this for a lighter weight of CallRecord.

Next is to make the AssertWasCalled methods to return the CallRecord. Since the AssertWasCalled can match multiple method invocations. I made them return an IList<CallRecord>.

With the CallRecord information on hand, an extension method below can easily compare the order of the calls:

        public static void Before(this IList<CallRecord> beforeCalls, IList<CallRecord> afterCalls)
        {
            long maxBefore = long.MinValue;
            CallRecord latestBeforeCall = null;
            foreach (var call in beforeCalls)
            {
                var sequence = call.Sequence;
                if (sequence > maxBefore)
                {
                    maxBefore = sequence;
                    latestBeforeCall = call;
                }
            }

            long minAfter = long.MaxValue;
            CallRecord earliestAfterCall = null;
            foreach (var call in afterCalls)
            {
                var sequence = call.Sequence;
                if (sequence < minAfter)
                {
                    minAfter = sequence;
                    earliestAfterCall = call;
                }
            }
            if (maxBefore>minAfter)
            {
                throw new ExpectationViolationException(
                    "Expected that calls to " + latestBeforeCall.Method + 
                    " occurs before " + earliestAfterCall.Method + 
                    ", but the expectation is not satisfied.");

            }
        }

Again, I was lazy, the exception message should have been better formed, for example including the more detailed method signature and the real parameters. (Update: the API has been enhanced)

With all those in place, the final bit is to create a test cases to verify it works.

    [TestFixture] public class BeforeExtensionMethodTest
    {
        public interface IBefore  { void MethodBefore(); }

        public interface IAfter { void MethodAfter(); }

        [Test] public void Before_succeeds_if_beforeCalls_occured_before_afterCalls()
        {
            var mockBefore = MockRepository.GenerateStub<IBefore>();
            var mockAfter = MockRepository.GenerateStub<IAfter>();
            mockBefore.MethodBefore();
            mockBefore.MethodBefore();
            mockAfter.MethodAfter();
            mockAfter.MethodAfter();
            mockAfter.MethodAfter();
            mockBefore.AssertWasCalled(b => b.MethodBefore())
                .Before(mockAfter.AssertWasCalled(a => a.MethodAfter()));
        }

        [ExpectedException(typeof(ExpectationViolationException))]
        [Test] public void Before_chokes_if_one_of_beforeCalls_occured_after_any_of_afterCalls()
        {
            var mockBefore = MockRepository.GenerateStub<IBefore>();
            var mockAfter = MockRepository.GenerateStub<IAfter>();
            mockBefore.MethodBefore();
            mockAfter.MethodAfter();
            mockBefore.MethodBefore();
            mockAfter.MethodAfter();
            mockAfter.MethodAfter();
            mockBefore.AssertWasCalled(b => b.MethodBefore())
                .Before(mockAfter.AssertWasCalled(a => a.MethodAfter()));
        }
    }

The full patch for r2212 of https://rhino-tools.svn.sourceforge.net/svnroot/rhino-tools/trunk/mocks/ can be downloaded here. Alex's original problem in the beginning now can be rewritten neatly.

        public void ViewTitleSetBeforeShownInWorkspace()
        {
            //arrange
            var mockView = MockRepository.GenerateMock<IView>();

            //act
            var target = new Presenter(mockView);
            target.Initialize();

            //assert
            mockView.AssertWasCalled(x => { x.Title = Arg<string>.Is.Anything; })
                .Before(mockView.AssertWasCalled(x => x.ShowInWorkspace("MyWorkspace")));
        }

Update 7/18: I made my customized version of Rhino Mocks available if you want to give it a try. It contains other enhancements.

Wednesday, June 24, 2009

How Good Is .Net Generics

People always criticize Java of not having a generics support as strong as .Net framework, which I totally agree. But in Java, I can easily specify a method parameter to take, for example, a list of T or any derived class of T. This is very usefully feature and you can see the use of this in the example below. When add, we can take any list of type T or its derived class. And we can also drainTo any list of type T or its supper class.

class MyList<T>
{
    public MyList(List<? extends T> initItems) {/*...*/}
    public void add(List<? extends T> items) {/*...*/}
    public void drainTo(List<? super T> items) {/*...*/}
}

Now, how can we do this in .Net? The closest feature to this is generic type constrain. You would probably attempt below in C#:

class MyList<T>
{
    public MyList<TDerived>(TDerived initItems) where TDerived : T {/*...*/} 
    public void Add<TDerived>(List<TDerived> items) where TDerived : T {/*...*/}
    public void DrainTo<TSuper>(List<TSuper> items) where T : TSuper {/*...*/}
}

Well, the only one actually works is the Add method. Unfortunately, the syntax is wrong for both the DrainTo method and the constructor. Constructor cannot take type parameter and the type constrain syntax is wrong in DrainTo.

I believe this is definitely the area that .Net generics support needs improvement in addition to the constrain of constrain issue. Seriously, the proper syntax for DrainTo may be more appropriate like below:

    public void DrainTo<TSuper>(List<TSuper> items) where TSuper : super T {/*...*/}

And I want type parameter in the constructors please.

Wednesday, June 10, 2009

Create Arbitrary Bound Array in C#

I have a need create an arbitrary bound array when write test cases for implementation of ICollection.CopyTo. C# doesn't support it as language feature but luckily, the Array class does allow it. Here is an helper class to make the task easier:

        public static Array NewArray<T>(int from, int to)
        {
            return Array.CreateInstance(
                typeof(T), // Array type
                new int[] { to - from + 1 }, // Size
                new int[] { from }); // lower bound
        }

With that, I can create an array like this: Array sales = NewArray<double>(1995, 2009);

Monday, June 08, 2009

How to Detected If Current Thread Is Interrupted in .Net

When porting an application from Java to C#. The missing of Thread.IsInterrupted in .Net making me to look for some alternatives. At this moment, I'm using the code below but if anyone come up with a better idea please let me know.

        public static bool IsCurrentThreadInterrupted()
        {
            try
            {
                Thread.Sleep(0); // get exception if interrupted.
            }
            catch (ThreadInterruptedException)
            {
                return true;
            }
            return false;
        }

Update (6/9/2009): Also found interesting article about Thread.Sleep:

Watch out for the .Net Stopwatch, ElapsedTicks != Elapsed.Ticks

Well, I was assuming that the Stopwatch returns ElapsedTicks measuring 1tick = 100ns as TimeSpan.Ticks does. Wasted more then an hour trying to debug a test case for multi-threaded application to find out that this is not the case. In order to get the measurement at the unit of 100ns, I need to use Stopwatch.Elapsed.Ticks!

Here is from the documentation:

Stopwatch ticks are different from DateTime.Ticks. Each tick in the DateTime.Ticks value represents one 100-nanosecond interval. Each tick in the ElapsedTicks value represents the time interval equal to 1 second divided by the Frequency.

Also, an good article about time measuring: Beware of the stopwatch