Get help with testing, discuss unit testing strategies etc.


Post by zombeerose »

I am not sure what you guys have planned for addressing the level of nesting that can occur when dealing with async tests so I will outline my current strategy in case it helps someone.

For complex tests, I have started defining sub-functions to group logical pieces. Each sub-function accepts a single argument, a callback function, which should be called once the tests in the sub-function are complete. I then added a couple helper/util methods to my "TestClass" that will call the sub-functions in sequence.

TestClass code:
Class('My.TestClass',{
    isa: Siesta.Test.ExtJS,
    methods: {
        /**
         * Utility method to execute a series of test functions in the order they were passed. 
         * This method accepts a variable number of arguments.
         * 
         * Each function argument should accept one parameter, a callback function. 
         * The callback function should be executed within the body of the function once 
         * processing has completed, which includes any async tests.
         * 
         * @param {Function} fn1
         * @param {Function} fn2
         * @param {Function} fn3
         * 
         * An Example:
         *     StartTest(function(t){
         *         function testA(cb){
         *              //do stuff
         *              //t.waitFor...
         *              cb();
         *         }
         *         
         *         function testB(cb){
         *              //do more stuff
         *              cb();
         *         }
         *         
         *         t.chain(testA,testB);
         *     });
         */
        chain: function(){
            var me = this,
                args = Array.prototype.slice.apply(arguments),
                i = 0,
                l = args.length,
                outerFn,
                innerFn;

            function closure(fn,cb){
                return function(){
                    fn.call(me,cb);
                }
            };
            
            for (i = l-1; i > 0; i--){
                if (!innerFn){
                    innerFn = args[i];
                }
                outerFn = args[i-1];
                
                innerFn = closure(outerFn,innerFn);
            }
            if (innerFn){
                innerFn.call(me);
            }
        },
        
        /**
         * Utility method just like {@link #chain} except that it will automatically execute this.done() as the last function in the chain.
         * 
         * @inheritdocs #chain
         */
        chainDone: function(){
            var me = this,
                args = Array.prototype.slice.apply(arguments);
            
            args.push(function(){ me.done(); });
            me.chain.apply(me,args);
        }
   }
});
Example of usage:
StartTest(function(t) {
    function testRender(cb){
       //do some rendering tests
       cb();
    }

    function testRows(cb){
       //do some more tests
       cb();
    }

    function testMenu(cb){
       //do some more tests
       t.waitForSomething(function(){
          cb();
       });
    }

    //execute each function in the order specified then call t.done() automatically as the last callback.
    t.chainDone(
        testRender,
        testRows,
        testMenu
    );
});
Make sense?
Last edited by zombeerose on Wed Jan 18, 2012 7:50 pm, edited 1 time in total.

Post by nickolay »

zombeerose wrote: Make sense?


Yes, pretty much.

This is exactly what we are planning as the 1st improvement - chaining with steps. Each step will be a function with the callback, or the object with some configs for typical tasks, like:
    StartTest(function(t) {
    
        //execute each function in the order specified [ then call t.done() automatically as the last callback ]
        t.chain[Done](
            function (next) {
               //do some rendering tests
               next();
            },
            {
                xtype   : 'click',
                domSel  : 'table.mycls'
            },
            {
                xtype   : 'drag',
                from    : ...,
                to      : ...
            }
        )
    });
    

Post by zombeerose »

Funny how similar the approach is - looking forward to it. :)

Post Reply