29 August 2012

WHAT - 测试工具

  • QUnit

    • An easy-to-use JavaScript Unit Testing framework.
  • Jasmine

    • DOM-less simple JavaScript testing framework
  • Vows

    • Asynchronous BDD & continuous integration for node.js
  • Mocha

    • mocha - simple, flexible, fun javascript test framework for node.js & the browser. (BDD, TDD, QUnit styles via interfaces)
  • Hiro

    • Hiro is a framework for testing third-party JavaScript applications. It runs each test suite in a separate sandbox preventing global state leaks and conflicts.
  • JsTestDriver
    • JsTestDriver aims to help javascript developers use good TDD practices and aims to make writing unit tests as easy as what already exists today for java with JUnit.
  • Buster.js

    • A powerful suite of automated test tools for JavaScript.
  • Sinon.js

    • Standalone and test framework agnostic JavaScript test spies, stubs and mocks.

WHAT - 什么是单元测试&自动化测试?

不用解释了吧。

WHAT - 为什么要做单元测试&自动化测试?

  • 验证程序正确性
  • 修复 bug 后的回归测试
  • 安全的代码重构
  • 缩短测试周期

HOW – Jasmine vs Qunit

基本结构

  • 测试套件&模块 suit
  • 测试用例 case
  • 断言 assertion

规范:CommonJS Unit Testing/1.1

Jasmine ['dʒæzmɪn; 'dʒæs-]

Jasmine 是行为驱动的 JavaScript 测试框架。不依赖于任何第三方 JavaScript 框架。不需要 DOM。拥有干净、明确的语法,可以容易的编写测试用例。

  • 优点:实现很完整,对于异步、同步测试的支持很好。

  • 缺点:不符合规范,写法语义化导致繁琐,方法太多。

The Jasmine Ruby Gem is for Rails, Ruby, or Ruby-friendly development

基本语法

describe("A suite", function() {
  it("contains spec with an expectation", function() {
    expect(true).toBe(true);
  });
});

QUnit

http://qunitjs.com/

QUnit 是一个强大、易用的 JavaScript 测试套件。它用于测试 jQuery 和插件,但是也适用于测试任何通用的 JavaScript 代码(甚至可用于服务端的 JavaScript 代码)。

  • 优先:清晰、高质的源码;符合 CommonJS Unit Test 规范。
  • 缺点:异步操作太繁琐(stop()、start())。

历史

QUnit 最初作为 jQuery 的一部分,由 John Resig 开发。2008年有了自己的主页、名称、API 文档,允许作为其他 JavaScript 代码的单元测试工具,此时它仍然依赖于 jQuery。2009年重写,QUnit 完全独立运行。 QUnit 的断言方法遵从 CommonJS Unit Test 规范,该规范在某种程度上受到了 QUnit 的影响。

基本语法

module( "group a" );
test( "a basic test example", function() {
    ok( true, "this test is fine" );
});
test( "a basic test example 2", function() {
    ok( true, "this test is fine" );
});

module( "group b" );
test( "a basic test example 3", function() {
    ok( true, "this test is fine" );
});
test( "a basic test example 4", function() {
    ok( true, "this test is fine" );
});

哪些开源库&框架在用 QUnit?

bootstrapjquerybackbonegrunt ...

HOW - Demo

QUnit + jQuery Queue

HOW - 最佳实践

  • 测试粒度(覆盖率)足够细
  • 按照业务模块组织测试代码
  • 与业务代码分离

WHY - QUnit 实现原理

  1. 初始化:用一个数组 config.queue 存放待执行的测试用例:

     config = {
         queue: [],
     };
     function synchronize( callback, last ) {
         config.queue.push( callback );
         if ( config.autorun && !config.blocking ) {
             process( last );
         }
     }
    
  2. 运行时:用一个 while 循环遍历数组 config.queue,从头部开始顺序执行:

     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()();
             } else {
                 window.setTimeout( next, 13 );
                 break;
             }
         }
         config.depth--;
         if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
             done();
         }
     }
    
  3. 异步操作:调用 stop() 后设置 config.blocking = true;调用 start() 后设置 config.blocking = false。如果 config.blocking 为 true,则会每隔 13ms 尝试恢复 while 循环。



blog comments powered by Disqus