ArcherXu 发表于 2012-12-22 21:28:42

QUnit源码阅读(2):test基本执行流程

QUnit源码阅读(2):test基本执行流程

<div class="postText"><div id="cnblogs_post_body"><div class="cnblogs_code">// 直接上代码

//step 1: write a simple test as the following.test("hello test", function() {    ok(1 == "1", "Passed!");});//step 2: 调用test函数QUnit = {    //...    test : function(testName, expected, callback, async) {      //...      //初始化test,      test = new Test({            name : name,            testName : testName,            expected : expected,            async : async,            callback : callback, //回调函数, very important            module : config.currentModule,            moduleTestEnvironment : config.currentModuleTestEnvironment,            stack : sourceFromStacktrace(2)      });      if (!validTest(test)) {            return;      }      test.queue();    },    //...}//step 3: 调用test.queue函数,在config.queue中存入test.init和queue的内置函数run。Test.prototype = {    //...    queue : function() {      var bad, test = this;      synchronize(function() {            test.init();      });      function run() {            // each of these can by async            synchronize(function() {                test.setup();            });            synchronize(function() {                test.run();            });            synchronize(function() {                test.teardown();            });            synchronize(function() {                test.finish();            });      }      // `bad` initialized at top of scope      // defer when previous test run passed, if storage is available      bad = QUnit.config.reorder && defined.sessionStorage && +sessionStorage.getItem("qunit-test-" + this.module + "-" + this.testName);      if (bad) {            run();      } else {            synchronize(run, true);      }    }    //...}//step 4.1 - 4.2 在config.queue中存入callback函数function synchronize(callback, last) {    config.queue.push(callback);    if (config.autorun && !config.blocking) {      process(last);    }}//step 5 调用Qunit.start函数QUnit.load = function() {    runLoggingCallbacks("begin", QUnit, {});    //I do not care, right now    //...    QUnit.init();    //...    if (config.autostart) {      QUnit.start();    }};//step 6, 调用 process(true)QUnit = {    //...    start : function(count) {      config.semaphore -= count || 1;      // don't start until equal number of stop-calls      if (config.semaphore > 0) {            return;      }      // ignore if start is called more often then stop      if (config.semaphore < 0) {            config.semaphore = 0;      }      // A slight delay, to avoid any current callbacks      if (defined.setTimeout) {            window.setTimeout(function() {                if (config.semaphore > 0) {                  return;                }                if (config.timeout) {                  clearTimeout(config.timeout);                }                config.blocking = false;                process(true);            }, 13);            //13ms后调用,即step 7      } else {            config.blocking = false;            process(true);      }    },    //...} //step 7: 调用 process(true)(function() {    if (config.semaphore > 0) {      return;    }    if (config.timeout) {      clearTimeout(config.timeout);    }    config.blocking = false;    process(true);    //ref step 8})()//step 8, 循环泵,整个test框架的调用驱动函数,将config.queue[]中的回调依次拿出来run//Attention: 利用函数window.setTimeout及next函数来不断循环的技巧☆☆☆function process(last) {    function next() {      process(last);    }    var start = new Date().getTime();    config.depth = config.depth ? config.depth + 1 : 1;    while (config.queue.length && !config.blocking) {      if (!defined.setTimeout || config.updateRate <= 0 || ((new Date().getTime() - start ) < config.updateRate )) {            config.queue.shift()();            //Attention, this is very important.      } else {            window.setTimeout(next, 13);            //Or, 13ms 之后再次调用process(true).            break;      }    }    config.depth--;    if (last && !config.blocking && !config.queue.length && config.depth === 0) {      done();    }}//step 9, 调用init函数Test.prototype = {    //...    init : function() {      //...    },    //...}//step 10. 调用run函数, 在 config.queue中放置更多的函数test.setup, run, teardown, finishTest.prototype = {    //...    queue : function() {      //...      function run() {            // each of these can by async            synchronize(function() {                test.setup();            });            synchronize(function() {                test.run();            });            synchronize(function() {                test.teardown();            });            synchronize(function() {                test.finish();            });      }      //...    }};//step 11. 调用test.setup, run, teardown, finishTest.prototype = {    //...    setup : function() {      //...    },    run : function() {      config.current = this;      var running = id("qunit-testresult");      if (running) {            running.innerHTML = "Running: <br/>" + this.name;      }      if (this.async) {            QUnit.stop();      }      //this.callback 将会调用我们在 step1中写的匿名函数function() { ok(1 == "1", "Passed!");})      //this.callback 的初始化请参考step2      if (config.notrycatch) {            this.callback.call(this.testEnvironment, QUnit.assert);            return;      }      try {            this.callback.call(this.testEnvironment, QUnit.assert);      } catch( e ) {            QUnit.pushFailure("Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + e.message, extractStacktrace(e, 0));            // else next test will carry the responsibility            saveGlobal();            // Restart the tests if they're blocking            if (config.blocking) {                QUnit.start();            }      }    },    teardown : function() {      //...    },    finish : function() {      //...    },};//step 12: 调用 我们的测试函数(function() {    ok(1 == "1", "Passed!");});//step 13: ok函数QUnit.assert = {    /**   * Asserts rough true-ish result.   * @name ok   * @function   * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );   */    ok : function(result, msg) {      //...      result = !!result;      //...    },    //...    equal : function(actual, expected, message) {      QUnit.push(expected == actual, actual, expected, message);    },}extend( QUnit, {    //...    push: function( result, actual, expected, message ) {      //...      message = escapeInnerText( message ) || ( result ? "okay" : "failed" );      //...          },    //... });
页: [1]
查看完整版本: QUnit源码阅读(2):test基本执行流程