Tuesday, April 27, 2004

I have added a new fixture, ProcessTestFixture, that implements the process testing presented by Marc Clifton in http://www.codeproject.com/csharp/autp3.asp.

A process is an ordered sequence of unit tests.  As long as one test passes, the next test is run. Due to the structure of MbUnit, this was straightforward to implement (I'll about this later in the blog). The syntax of the fixture is similar to Marc Clifton example but I have merge Test, Sequence(...) to TestSequence(...):

[ProcessTestFixture]
public MyProcess
{
    [TestSequence(1)]
    public void Hello()
    {...}
    [TestSequence(2)]
    public void World()
    {...}
    ...
}

The implementation of the fixture was done by the following steps:

  1. Create TestSequenceAttribute, a simple class inherited from TestPatternAttribute that stores the order,
    [AttributeUsage(AttributeTargets.Method, AllowMultiple=false, Inherited=true)]
    public sealed class TestSequenceAttribute : TestPatternAttribute
    {
        private int order;
      
        public TestSequenceAttribute(int order)
          {
            this.order = order;
        }
    
        public int Order
        {
            get
            {
                    return this.order;
            }
            set
            {
                this.order = value;
            }
        }
    }
  2. Create ProcessMethodRun, which implements IRun. This is where the "process" logic is created, more specifically in the Reflect method: since this method builds the tree of IRunInvoker instance, creating a process is just a matter of creating a sequence of MethodRunInvoker:
    public class ProcessMethodRun : IRun
    {
        ...
        public virtual void Reflect(
    			        RunInvokerTree tree, 
    			        RunInvokerVertex parent, 
            Type t
        )
        {
            // first gather all methods, with order.
            ArrayList methods = new ArrayList();
            foreach(MethodInfo mi in 
                    TypeHelper.GetAttributedMethods(t,this.AttributeType))
            {
                // get sequence attribute
                TestSequenceAttribute seq = 
                    (TestSequenceAttribute)TypeHelper.GetFirstCustomAttribute(mi,typeof(TestSequenceAttribute)); 
                methods.Add( new OrderedMethod(mi, seq.Order) ); 
            }
    
            // sort the methods
            QuickSorter sorter = new QuickSorter();
            sorter.Sort(methods);
    
            // populate execution tree.
            RunInvokerVertex child = parent;
            foreach(OrderedMethod om in methods)
            {
                IRunInvoker invoker = InstanceInvoker(om.Method);
                child = tree.AddChild(child,invoker);
            } 
        }
    
        protected IRunInvoker InstanceInvoker(MethodInfo mi)
        {
            IRunInvoker invoker = new MethodRunInvoker(this,mi);
            return DecoratorPatternAttribute.DecoreInvoker(mi,invoker);
        }
    
        #region OrderedMethod
        private class OrderedMethod : IComparable
        {
            private MethodInfo method;
            private int order;
       
            public  OrderedMethod(MethodInfo method, int order)
            {
                this.method = method;
                this.order = order;
            }
    
    
            public MethodInfo Method
            {
                get
                {
                    return this.method;
                }
            }
            public int Order
            {
                get
                {
                    return this.order; 
                }
            }
            public int CompareTo(OrderedMethod obj)
            {
                return this.order.CompareTo(obj.order);
            }
       
            int IComparable.CompareTo(Object obj)
            {
                return this.CompareTo((OrderedMethod)obj);
            }
        }
        #endregion
    	}
  3. Create ProcessTestFixtureAttribute, a class that inherits from TestFixturePatternAttribute and defines the fixture execution pipe:
    public class ProcessTestFixtureAttribute : TestFixturePatternAttribute 
    {
        public override IRun GetRun()
        {
            SequenceRun runs = new SequenceRun();
       
            OptionalMethodRun setup = new OptionalMethodRun(typeof(SetUpAttribute),false);
            runs.Runs.Add( setup );
       
            ProcessMethodRun test = new ProcessMethodRun(typeof(TestSequenceAttribute));
            runs.Runs.Add(test);
       
            OptionalMethodRun tearDown = new OptionalMethodRun(typeof(TearDownAttribute),false);
            runs.Runs.Add(tearDown);
       
            return runs;      
        }
    }

Et voilà!

posted on Tuesday, April 27, 2004 7:39:00 PM UTC  #    Comments [2]
Tracked by:
"heart palpitation" (online) [Trackback]
Monday, June 06, 2005 6:10:14 PM UTC
Peli's Blog
Monday, June 06, 2005 6:10:15 PM UTC
Peli's Blog
Comments are closed.