<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>幼学笔记 &#187; QUnit</title>
	<atom:link href="http://www.oncoding.cn/tag/qunit/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.oncoding.cn</link>
	<description>追寻简单生活</description>
	<lastBuildDate>Sun, 29 May 2011 14:03:07 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>JavaScript单元测试工具 — QUnit</title>
		<link>http://www.oncoding.cn/2010/javascript-unit-testing-qunit/</link>
		<comments>http://www.oncoding.cn/2010/javascript-unit-testing-qunit/#comments</comments>
		<pubDate>Thu, 04 Feb 2010 04:32:47 +0000</pubDate>
		<dc:creator>j5726</dc:creator>
				<category><![CDATA[前端]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[QUnit]]></category>
		<category><![CDATA[单元测试]]></category>

		<guid isPermaLink="false">http://www.oncoding.cn/?p=629</guid>
		<description><![CDATA[QUnit是jQuery团队开发的JavaScript单元测试工具，使用方便，界面美观。近期试用了一下并进一步了解了JavaScript单元测试，记录一下所思所得。 什么是单元测试 单元测试又称为模块测试，是针对程序模块(软件设计的最小单位)来进行正确性检验的测试工作。单元测试主要是用来检验程式的内部逻辑，也称为个体测试、结构测试或逻辑驱动测试。通常由撰写程式码的程式设计师负责进行。 通常来说，程式設計師每修改一次程式就會進行最少一次單元測試，在編寫程式的過程中前後很可能要進行多次單元測試，以證實程式達到軟件規格書(en:Specification)要求的工作目標，沒有臭蟲；雖然单元测试不是什么必须的，但也不坏，這牽涉到專案管理的政策決定。 —— 维基百科 (中文，英文) 为什么JavaScript需要单元测试 由于存在浏览器解析环境、用户操作习惯等差异，前端程序的许多问题是无法捕捉或重现的，现在前端程序的测试多是黑盒测试，即靠点击点击点击来寻找程序bug。这种方式既费时费力，又无法保证测试的覆盖面。 同时，前端逻辑和交互越来越复杂，和其他编程语言一样，一个函数，一个模块，在修改bug或添加新功能的过程中，很容易就产生新的bug，或使老的bug复活。这种情况下，反复进行黑盒测试，其工作量和测试质量是可想而知的。 此外，浏览器兼容性测试是前端程序测试的重要一环，在多个浏览器之间测试前端程序，上面说的工作量就会成n倍的增加。 为什么我们的前端程序如此脆弱？就是因为没用单元测试。。 假如使用了单元测试，上边的问题就变得很容易了，当然前提是你要花时间去研究和编写测试用例。 根据函数或模块的源代码，编写出包含各种情况的测试用例，每次解决bug或添加新功能，都随时更新这个用例然后进行测试，很容易就找出新bug和“复活”的老bug。 测试兼容性，只需要在不同的浏览器中分别运行这个测试，问题就一目了然了。 也许白盒比黑盒要多费几倍的脑子，但想想我们那脆弱的程序，想想那些随时冒出来的烦人的老bug，费点脑子，值了！ 使用QUnit 注：下面的内容主要参考了 QUnit文档 和 NetTuts+的这篇文章。 建立一个测试页面，引入 qunit.js 和 qunit.css 这两个必需的文件，这两个文件是存放在github上的，鉴于目前操蛋的互联网环境，最好下载到本地调用。 注：body中的元素id命名必须依照如下形式，否则无法正常显示。 测试示例 下面是一个最简单的函数测试用例，解释请见程序注释。 module( name, [lifecycle] ) 函数指定测试模块和周期。 ok( state, [message] ) 是QUnit中最常用的一个判断函数，只能判断true和false。 DEMO在这里，看一下测试结果： 结果都是绿的，说明两条测试语句都符合设定的规则。可以尝试修改下规则 就可以看到爆红了。。 更多测试判断 除了ok()之外，QUnit还有如下几个判断函数： 相等判断equals( actual, expected, [message] ) 示例： 相同判断(包含数组、对象等)same( actual, expected, [message] ) [...]]]></description>
			<content:encoded><![CDATA[<p>QUnit是jQuery团队开发的JavaScript单元测试工具，使用方便，界面美观。近期试用了一下并进一步了解了JavaScript单元测试，记录一下所思所得。</p>
<h3>什么是单元测试</h3>
<blockquote><p>单元测试又称为模块测试，是针对程序模块(软件设计的最小单位)来进行正确性检验的测试工作。单元测试主要是用来检验程式的内部逻辑，也称为个体测试、结构测试或逻辑驱动测试。通常由撰写程式码的程式设计师负责进行。</p>
<p>通常来说，程式設計師每修改一次程式就會進行最少一次單元測試，在編寫程式的過程中前後很可能要進行多次單元測試，以證實程式達到軟件規格書(en:Specification)要求的工作目標，沒有臭蟲；雖然单元测试不是什么必须的，但也不坏，這牽涉到專案管理的政策決定。</p>
<p>—— 维基百科 (<a href="http://zh.wikipedia.org/wiki/%E5%8D%95%E5%85%83%E6%B5%8B%E8%AF%95" target="_blank">中文</a>，<a href="http://en.wikipedia.org/wiki/Unit_testing" target="_blank">英文</a>)</p></blockquote>
<h3>为什么JavaScript需要单元测试</h3>
<p><span id="more-629"></span><br />
由于存在浏览器解析环境、用户操作习惯等差异，前端程序的许多问题是无法捕捉或重现的，现在前端程序的测试多是<a href="http://zh.wikipedia.org/zh-cn/%E9%BB%91%E7%9B%92%E6%B5%8B%E8%AF%95" target="_blank">黑盒测试</a>，即靠点击点击点击来寻找程序bug。这种方式既费时费力，又无法保证测试的覆盖面。</p>
<p>同时，前端逻辑和交互越来越复杂，和其他编程语言一样，一个函数，一个模块，在修改bug或添加新功能的过程中，很容易就产生新的bug，或使老的bug复活。这种情况下，反复进行黑盒测试，其工作量和测试质量是可想而知的。</p>
<p>此外，浏览器兼容性测试是前端程序测试的重要一环，在多个浏览器之间测试前端程序，上面说的工作量就会成n倍的增加。</p>
<p><strong>为什么我们的前端程序如此脆弱？就是因为没用单元测试。。</strong></p>
<p>假如使用了单元测试，上边的问题就变得很容易了，当然前提是你要花时间去研究和编写测试用例。</p>
<p>根据函数或模块的源代码，编写出包含各种情况的测试用例，每次解决bug或添加新功能，都随时更新这个用例然后进行测试，很容易就找出新bug和“复活”的老bug。</p>
<p>测试兼容性，只需要在不同的浏览器中分别运行这个测试，问题就一目了然了。</p>
<p>也许白盒比黑盒要多费几倍的脑子，但想想我们那脆弱的程序，想想那些随时冒出来的烦人的老bug，费点脑子，值了！</p>
<h3>使用QUnit</h3>
<p>注：下面的内容主要参考了 <a href="http://docs.jquery.com/QUnit" target="_blank">QUnit文档</a> 和 <a href="http://net.tutsplus.com/tutorials/javascript-ajax/how-to-test-your-javascript-code-with-qunit" target="_blank">NetTuts+的这篇文章</a>。</p>
<p>建立一个测试页面，引入 <a href="http://github.com/jquery/qunit/raw/master/qunit/qunit.js" target="_blank">qunit.js</a> 和 <a href="http://github.com/jquery/qunit/raw/master/qunit/qunit.css" target="_blank">qunit.css</a> 这两个必需的文件，这两个文件是存放在github上的，鉴于目前操蛋的互联网环境，最好下载到本地调用。</p>
<p>注：body中的元素id命名必须依照如下形式，否则无法正常显示。</p>
<pre class="brush: xml; title: ; notranslate">
&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.01 Transitional//EN&quot; &quot;http://www.w3.org/TR/html4/loose.dtd&quot;&gt;
&lt;html&gt;
&lt;head&gt;
  &lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=UTF-8&quot;&gt;
  &lt;link rel=&quot;stylesheet&quot; href=&quot;http://github.com/jquery/qunit/raw/master/qunit/qunit.css&quot; type=&quot;text/css&quot; media=&quot;screen&quot; /&gt;
  &lt;script type=&quot;text/javascript&quot; src=&quot;http://github.com/jquery/qunit/raw/master/qunit/qunit.js&quot;&gt;&lt;/script&gt;
&lt;/head&gt;
&lt;body&gt;
  &lt;h1 id=&quot;qunit-header&quot;&gt;QUnit example&lt;/h1&gt;
  &lt;h2 id=&quot;qunit-banner&quot;&gt;&lt;/h2&gt;
  &lt;h2 id=&quot;qunit-userAgent&quot;&gt;&lt;/h2&gt;
  &lt;ol id=&quot;qunit-tests&quot;&gt;&lt;/ol&gt;
&lt;/body&gt;
&lt;/html&gt;
</pre>
<h3>测试示例</h3>
<p>下面是一个最简单的函数测试用例，解释请见程序注释。</p>
<pre class="brush: jscript; title: ; notranslate">
    //定义测试模块
    module( &quot;测试示例&quot; );
    //定义一个简单的函数，判断参数是不是数字
    function simpleTest(para) {
      if(typeof para == &quot;number&quot;) {
        return true;
      }
      else{
        return false;
      }
    }
    //开始单元测试
    test('simpleTest()', function() {
      //列举各种可能的情况，注意使用 ! 保证表达式符合应该的逻辑
      ok(simpleTest(2), '2是一个数字');
      ok(!simpleTest(&quot;2&quot;), '&quot;2&quot;不是一个数字');
    });
</pre>
<p><a href="http://docs.jquery.com/QUnit/module#namelifecycle" target="_blank">module( name, [lifecycle] ) </a>函数指定测试模块和周期。</p>
<p><a href="http://docs.jquery.com/QUnit/ok#statemessage" target="_blank">ok( state, [message] ) </a>是QUnit中最常用的一个判断函数，只能判断true和false。</p>
<p><a href="http://www.oncoding.cn/demos/qunit" target="_blank">DEMO在这里</a>，看一下测试结果：</p>
<p class="aligncenter">
<div class="wp-caption " style="width:336px"><img class="size-full wp-image-644" title="qunit" src="http://www.oncoding.cn/wp-content/uploads/2010/02/qunit.jpg" alt="" width="326" height="227" /></div>
</p>
<p>结果都是绿的，说明两条测试语句都符合设定的规则。可以尝试修改下规则</p>
<pre class="brush: jscript; title: ; notranslate">
//...
ok(simpleTest(&quot;2&quot;), '&quot;2&quot;是一个数字');
//...
</pre>
<p>就可以看到爆红了。。</p>
<h3>更多测试判断</h3>
<p>除了ok()之外，QUnit还有如下几个判断函数：</p>
<h4>相等判断<a href="http://docs.jquery.com/QUnit/equals#actualexpectedmessage" target="_blank">equals( actual, expected, [message] ) </a></h4>
<p>示例：</p>
<pre class="brush: jscript; title: ; notranslate">
  //定义一个简单的函数，返回数字和2的乘积
    function simpleTest1(para) {
      return para * 2;
    }
    //开始单元测试
    test('simpleTest1()', function() {
      //列举各种可能的情况
      equals(simpleTest1(2), 4, '2 * 2 等于 4');
      equals(simpleTest(2), 3, '2 * 2 等于 3');
    });
</pre>
<h4>相同判断(包含数组、对象等)<a href="http://docs.jquery.com/QUnit/same#actualexpectedmessage" target="_blank">same( actual, expected, [message] ) </a></h4>
<p>示例：</p>
<pre class="brush: jscript; title: ; notranslate">
  //定义一个简单的函数，返回一个数组
    function simpleTest2() {
      return [1, 2];
    }
    //开始单元测试
    test('simpleTest2()', function() {
      //列举各种可能的情况
      equals(simpleTest2(), [1, 2], '函数返回数组[1, 2]');
      equals(simpleTest2(), [1, 1], '函数返回数组[1, 1]');
    });
</pre>
<p>same()和意思和equals()差不多，但same()可以判断数组、对象等的相同，而equals不能。</p>
<h4>异步与Ajax</h4>
<p>对于异步程序的测试，如setTimeout、setInterval、Ajax等情况，按照上面的方法，在异步调用执行之前，测试就已完成并输出了结果。这时，配合使用QUnit提供的两个函数：<a href="http://docs.jquery.com/QUnit/stop#timeout" target="_blank">stop( [timeout] ) </a> 和 <a href="http://docs.jquery.com/QUnit/start" target="_blank">start()</a>，也可以轻松搞定。</p>
<p>直接看例子：</p>
<pre class="brush: jscript; title: ; notranslate">
    //异步测试
    module( &quot;异步测试示例&quot; );
    //setTimeout
    test('asynchronous test', function() {
      // 暂停测试
      stop();

      setTimeout(function() {
        ok(true, '完成运行');
        //待测试完成后，恢复
        start();
      }, 100)
    })
    //另一种形式
    asyncTest('asynchronous test', function() {
      setTimeout(function() {
        ok(true);
        //待测试完成后，恢复
        start();
      }, 100)
    })
</pre>
<p>Ajax也是类似的道理：</p>
<pre class="brush: jscript; title: ; notranslate">
    //Ajax测试
    function ajax(successCallback) {
      $.ajax({
        url: 'server.php',
        success: successCallback
      });
    }

    test('asynchronous test', function() {
      // 暂停测试
      stop();

      ajax(function() {
        // 异步调用判断
      })

      setTimeout(function() {
        //异步测试完成后，恢复
        start();
      }, 2000);
    })
</pre>
<h3>了解更多</h3>
<blockquote>
<ul>
<li><a href="http://docs.jquery.com/QUnit" target="_blank">QUnit文档</a></li>
<li><a href="http://net.tutsplus.com/tutorials/javascript-ajax/how-to-test-your-javascript-code-with-qunit" target="_blank">How to Test your JavaScript Code with QUnit</a></li>
<li><a href="http://www.swift-lizard.com/2009/11/24/test-driven-development-with-jquery-qunit/" target="_blank">Development with jQuery &amp; Qunit</a></li>
<li><a href="http://testswarm.com/" target="_blank">TestSwarm</a></li>
</ul>
</blockquote>
<p style="text-align: right;"><a href="http://www.oncoding.cn/2010/javascript-unit-testing-qunit/">幼学笔记</a>原创内容，根据<a href="http://creativecommons.org/licenses/by-nc-sa/2.5/">CC协议</a>发布，欢迎具名转载。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.oncoding.cn/2010/javascript-unit-testing-qunit/feed/</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
	</channel>
</rss>

