Saturday, September 20, 2008

Testing the composite pattern - reusable test helpers

I face quite often the need to test a composite pattern variations. And truly was duplicating some similar code around. As tests are now my focus for self-improvement (and always, should I be eaten alive by the tdd purists if I lie), I decided to extract some of the snippets into reusable helper methods.
Here is what I got for the calling of the composite pattern "operation":

The usage:

CompositePatternTestHelper.TestForCompositeOperation<ProcessCoordinator, IProcess>(
                parent => parent.Stop(), // Parent operation
                child => child.Stop(), // Should invoke following on every child
                (parent, child) => parent.Processes.Add(child) // How to add add child to the parent
                );

And for the helper method/class implementation (The most recent version available at http://code.google.com/p/toolsdotnet/source/browse/trunk/Tools.Net/src/Tools.Tests.Helpers/CompositePatternTestHelper.cs):

using System;
using Rhino.Mocks;
 
namespace Tools.Tests.Helpers
{
    public static class CompositePatternTestHelper
    {
        /// <summary>
        /// Helper method to test composite [parent/child] pattern implementation, where calls
        /// to the parent result into calls onto its children.
        /// </summary>
        /// <remarks>Creates the parent object using its default constructor</remarks>
        public static void TestForCompositeOperation<ParentType, ChildType>(Action<ParentType> parentAction, Action<ChildType> childAction, Action<ParentType, ChildType> addChild)
            where ChildType : class
            where ParentType : new()
        {
            // Requires a default ctor to exists
            var parent = new ParentType();
 
            TestForCompositeOperation(parent, parentAction, childAction, addChild);
        }
        /// <summary>
        /// Helper method to test composite [parent/child] pattern implementation, where calls
        /// to the parent result into calls onto its children.
        /// </summary>
        /// <remarks>Uses the passed in instance of a parent</remarks>
        public static void TestForCompositeOperation<ParentType, ChildType>(ParentType parent, 
            Action<ParentType> parentAction, Action<ChildType> childAction, Action<ParentType, ChildType> addChild)
            where ChildType : class
        {
            // Use Rhino.Mocks to create stubs
            var child1 = MockRepository.GenerateStub<ChildType>();
            var child2 = MockRepository.GenerateStub<ChildType>();
            // Setup two children, the arbitrary choice, but should not really matter
            child1.Expect(childAction);
            child1.Expect(childAction);
            // Add children to the parent
            addChild(parent, child1);
            addChild(parent, child1);
            // Call parent action
            parentAction(parent);
            // Assert parent action resulted in the calls to children
            child1.AssertWasCalled(childAction);
            child1.AssertWasCalled(childAction);
        }
    }
}
Post a Comment