unit test 與 AsUnit 3.0 - tutorial (2/3)
目前 asUnit的最新版是 asUnit 3.0.1 alpha,據兩位負責人說這是多年以來最大的改版,完全使用 actionscirpt 3 語法,並且忠實的照者 JUnit 去刻出一樣的功能,因此對大部份熟悉 JUnit使用方式的工程師來說,只要記得把 type 改成放後面並加上 : 就可以直接開工了。
下面簡單說明一下 asUnit 3的用法。
假設你有一個叫做 Money的class,它的功能是用來加減運算金額的數目
(note:這個程式是從 as2unit裏面借來的,我將它改寫成AS3 語法並修掉一些錯誤以通過測試)
-
package{
-
-
class Money {
-
-
private var __pounds:Number;
-
private var __pence:Number
-
-
public function Money( pounds:Number, pence:Number )
-
{
-
/*
-
if ( pounds == undefined || pence == undefined )
-
throw new Error( "Invalid constructor arguments" );
-
*/
-
-
if ( pence> 100 )
-
{
-
pounds = pounds + Math.floor( pence / 100 );
-
pence = pence % 100;
-
}
-
//it's using setters here, for updating __pounds indeed.
-
this.pounds = pounds;
-
this.pence = pence;
-
}
-
-
-
//------------------------------------------------------------------------------
-
-
public function addMoney( money:Money ):Money
-
{
-
var pounds:Number = this.pounds;
-
var pence:Number = this.pence;
-
-
pounds = pounds + money.pounds;
-
pence = pence + money.pence;
-
-
return flatten( pounds, pence );
-
}
-
}
-
}
在這個class裏目前只有一個method,叫做 addMoney。
以往我們要測試這個class會不會通過,可能會用類似下面的程式:
-
var m:Money = new Money(5,10);
-
m.addMoney(new Money(2,10));
-
trace(m)
然後看結果是不是如預期中的金額。
這很明顯的,這樣做非常沒有效率,而且當class結構越長越大時,就很難維護這些test code。
因此比較好的做法是寫一個獨立的 test class,像這樣:
-
package{
-
-
/*
-
這裏是真正的 test class, 測試每一支 method
-
*/
-
-
import flash.util.*;
-
import Money;
-
import asunit.framework.TestCase;
-
import asunit.framework.TestSuite;
-
-
public class TestMoney extends TestCase{
-
-
private var money:Money;
-
-
/**/
-
public function TestMoney( ... args:Array )
-
{
-
trace("abba:"+ args);
-
super( args[0] );
-
}
-
-
-
//------------------------------------------------------------------------------
-
-
public function testAddMoney()
-
{
-
var pounds2:Number = 3;
-
var pence2:Number = 20;
-
-
money = new Money( 3, 50 );
-
-
-
var money2:Money = new Money( pounds2, pence2 );
-
-
var money3:Money = money.addMoney( money2 )
-
/*
-
//assertNotNull( "money was null", money3 );
-
//assertNotUndefined( "money was undefined", money3 );
-
*/
-
assertEquals( "Pounds should be 6", 6, money3.pounds );
-
assertEquals( "Pence should be 70", 70, money3.pence );
-
-
}
-
}
-
}
在這個class裏可以看到許多 assertEquals(), assertNotNull()之類的method, 這些就是 asUnit提供的測試功能,以 testAddMoney()為例,我們用一個新數字加上原本的數字後,透過
assertEquals( "Pounds should be 6", 6, money3.pounds ); 來檢查加總的結果是否為 6,也就是將 money3.pounds 當做參數傳入,然後看看程式跑完後跳出來的數字是否為6,如果兩者相等,那這個測試就通過,如果不是,那就要開始debug囉~
由上面兩個例子可以類推,如果未來 Money class裏又增加了下列功能:
subtractMoney()
greaterThan()
lessThan()
equals()
勢必每個method都可以透過一個 testXXXX()來進行測試,透過這樣系統化的撰寫test code,不但可以確保程式如預期般的運作,更重要的是未來不論要修改,或是人事交替必需由新進工程師接手維護程式碼,都可以透過這組 test code來確保程式功能完整無誤。
asUnit另一個更棒的功能就是 test suite (唸做 sweet),可以將一堆test class集合起來一次執行,請看範例:
-
package{
-
import asunit.framework.TestSuite;
-
-
import TestMoney, TestCar, TestObject;
-
import flash.util.*;
-
-
/*
-
aggregates all test classes here to run at once
-
*/
-
public class MyTestSuite extends TestSuite{
-
-
public function MyTestSuite(){
-
addTest(new TestMoney());
-
addTest(new TestCar());
-
addTest(new TestObject());
-
}
-
}
-
}
這裏我們建了一個 MyTestSuite,並且將三個要測試的class (別別是 TestMoney, TestCar, TestObject) 都丟進去,將來只要執行這個 MyTestSuite就可以一次測試完三個class裏所有的method。
測試語法如下:
-
mt:MyTestSuite = new MyTestSuite();
-
mt.run();
不過這樣做有個小缺點,就是除非執行過程中有發生錯誤,才會在eclipse的console中顯示錯誤訊息,但如果全部通過的話就完全不會顯示任何資訊。
為此asUnit很貼心的提供了兩種選擇,第一個是用 flex 畫出來的測試介面,使用方法如下:
-
package {
-
import asunit.textui.TestRunner;
-
import TestMoney;
-
-
public class AsUnit extends TestRunner {
-
-
public function AsUnit() {
-
start(MyTestSuite); //this is for multiple test sets
-
//start(TestMoney); //this is for single test set
-
}
-
}
-
}
只要把MyTestSuite傳進去,它就會自動執行並開啟一個小swf視窗,最後把結果顯示在裏面,如下圖:

從圖中可以看出只花了0.025秒就完成了12項測試並且全部通過。
另一個方法則是用xul ui。xul是一個可以在 firefox裏執行的 GUI app,使用方式也差不多,只是他得在browser裏面執行,但由於我不需要這種玩意所以抓回來後從來沒執行過。


Trackback this post | Subscribe to the comments via RSS Feed