iT邦幫忙

DAY 15
5

node.js伺服器實戰系列 第 15

node.js伺服器實戰(15) - 單元測試

  • 分享至 

  • xImage
  •  

就先從基本的單元測試開始,看看有哪些工具可以使用。
node.js可用的單元測試工具

node.js的單元測試工具其實不少,node.js核心模組也有提供assertion的支援。之前看過的工具重要的有:

  1. expresso:這是connect/express這幾個著名的模組套件的作者們開發的單元測試框架,用的人很多,還支援測試覆蓋率
  2. vow:這是一個BDD的單元測試框架,換言之,可以用他的meta語法定義介面需求,然後做測試
  3. nodeunit:一個蠻簡單的單元測試框架,使用方式也很直覺

在node.js中做單元測試,有一個重點是要能支援在非同步的操作中,也能進行單元測試,這幾個框架都能支援。不過expresso跟vow感覺比nodeunit複雜一點,所以我就選了nodeunit。因為我看過他的readme,就可以寫出單元測試了,學起來很快。

nodeunit可以透過一個命令列工具直接驅動測試,還可以選擇不同的報告格式。可以傳送單個測試的js檔案給它,或是整個目錄,它就會把目錄中的單元測試js檔都執行一次。

一個簡單的nodeunit單元測試長這樣:

 exports.testSomething = function(test){
     test.expect(1);
     test.ok(true, "this assertion should pass");
     test.done();
 };
 
 exports.testSomethingElse = function(test){
     test.ok(false, "this assertion should fail");
     test.done();
 };

它會用參數傳送一個test物件給每個單元測試函數,使用test.expect(n)告訴它會有多少個assertion,測試結束則呼叫test.done()。需要做的動作就只有這些。

另外,它還支援test suite,利用這個還可以寫簡單的setup與teardown,來初始化一些測試環境。另外,還可以用group方式把幾個測試函數及合成群組。

 var testCase = require('nodeunit').testCase;
 
 module.exports = testCase({
     setUp: function (callback) {
         this.foo = 'bar';
         callback();
     },
     tearDown: function (callback) {
         // clean up
         callback();
     },
     test1: function (test) {
         test.equals(this.foo, 'bar');
         test.done();
     }
 });

使用testCase,可以讓測試程式組織更清楚。

幾個單元測試的例子

首先,要把之前寫的testroute.js來改寫成單元測試...不過寫一些會發現,測試起來有點複雜,尤其在測試addhost時,所以稍微調整一下程式,增加一個checkhost函數,其他程式維持不變:

 ......
 function checkhost(host) {
     var a = cache.get(host, 'fs');
     var b = cache.get(host, 'route');
     if(typeof a == 'undefined' || typeof b == 'undefined') {
         return false;
     } else {
         return true;
     }
 }
 
 module.exports = {
     addhost: addhost,
     addfs: addfs,
     addroute: addroute,
     query: query,
     checkhost: checkhost
 };

這樣就可以用比較簡單的方式測試addhost:

 var testCase = require('nodeunit').testCase;
 
 module.exports = testCase({
     setUp: function(cb) {
         this.router = require('../lib/router');
         cb();
     },
     tearDown: function(cb) {
         this.router = null;
         cb()
     },
     "testAddHost": function(test) {
         test.expect(1);
         var host = 'nodejs.org';
         this.router.addhost(host);
         test.ok(this.router.checkhost(host));
         test.done();
     }
 });

然後先用nodeunit來跑跑看...咦?怎麼出錯了...可疑點在nodeunit/bin/nodeunit的十四行:

 var args = process.ARGV.slice(2);

原來這週node-v0.6.0準備釋出,我使用的node-v0.5.10已經先把一些過時的API刪掉了XD...只要把ARGV改為小寫就可以了,跑出來的測試結果:

 Feng-Hsu-Pingteki-MacBook-Air:evolve fillano$ nodeunit tests/testroute.js 
 
 testroute.js
 ✔ testAddHost
 
 OK: 1 assertions (56ms)
 Feng-Hsu-Pingteki-MacBook-Air:evolve fillano$

另外,在nodeunit/deps/ejs.js裡面使用了就的模組名稱,雖然不影響執行,但是每次跑都會出現一些提示訊息,也蠻討厭的,一起改掉吧。

 require('sys') => require('util')

這樣就沒多大問題了。

與ant整合

改寫一下之前做的build.xml,讓它可以驅動nodeunit:

 <?xml version="1.0"?>
 <project name="evolve">
   <target name="unittest">
     <exec executable="D:/node/bin/nodeunit.cmd">
         <arg value="tests/testroute.js" />
     </exec>
   </target>
   <target name="integrate">
   </target>
   <target name="coverage-init">
   </target>
   <target name="coverage" depends="coverage-init">
   </target>
   <target name="lint">
   </target>
   <target name="alltest" depends="lint,coverage,unittest,integrate">
   </target>
   <target name="dummy">
   </target>
 </project>

然後跑ant unittest來執行單元測試:

怎麼跑出奇怪的東西啦...看起來是因為做彩色輸出以及utf-8符號的關係,只好稍微調整他的外觀,拿他的eclipse.js這個reporter改一改,把utf-8符號以及顏色的escape code改掉,取名為ant.js,然後修改nodeunit/lib/reporters/index.js,把ant.js加進去,接下來只要在build.xml多加reporter的參數(怎麼使用參數,其實直接行nodeunit時,就會跑出說明)。這樣,就可以正常跑出單元測試結果了:

 D:\fillano\Dropbox\Shared\evolve>ant unittest
 Buildfile: D:\fillano\Dropbox\Shared\evolve\build.xml
 
 unittest:
      [exec]
      [exec] testroute.js
      [exec] ok: testAddHost
      [exec]
      [exec] OK: 1 assertions (8ms)
 
 BUILD SUCCESSFUL
 Total time: 0 seconds

可以正常輸出後,就可以撰寫更多的單元測試。

相關文章


上一篇
node.js伺服器實戰(14) - 自動化
下一篇
node.js伺服器實戰(16) - 可測試性
系列文
node.js伺服器實戰33
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言