engineering > 裏所有文章列表
testing這件事對許多工程師來說都是:知道它很重要,但從來不覺得應該去做。
在瞭解如何使用 AsUnit這樣一個 test framework後,接者就可以來談談目前一般人進行testing的方式。
比較傳統的做法是先寫程式,然後再做 unit test,也就是程式碼寫好後再用一堆 test case去驗証它的正確性,這種做法初看是非常合理的,也符合一般常見的專案開發流程,先規畫、再寫code、最後測試,然後上線(我們就叫這種為 waterfall開發法)
但這種做法也有不少的缺點,最明顯的一個就是等到全部的code都寫好時才要進行測試,往往會覺得無從下手,因此此時可能已經有數十個class,而且彼此的關連極深,根本不知道該怎麼測起,搞不好連當初寫的工程師自已都忘了某個class是做什麼用的(別笑,你試試看自已寫個class不加註解,然後半年後再拿出來,看看你還能記得多少內容或理解它在做什麼)。
另一個麻煩就是此時才進行測試,即使發現了錯誤,恐怕也很難修改,或是能改但成本變的很大,因為這時一改恐怕就要牽動好幾個其它class,天知道改了這裏其它地方會不會爆炸。
有鑑於此,90年代未期開始出現一種新的聲音,強調不如在寫程式前先把 test case寫好,然後再以通過測試為目標去開發程式,這就是所謂的 test-driven design。
舉個簡單的例子,以前面的money class為例,傳統的劇情是這樣:
1、我希望這個class可以加總兩筆金額,例如原本3元,加上5元後得到結果 8元
2、然後開始寫 Money.addMoney() 這支method:function addMoney(){....}
3、寫好後用幾組不同的數字傳入 addMoney() 去看看結果是否正確
而在 test-driven的劇情則是這樣:
1、我希望這個class可以加總兩筆金額,例如原本3元,加上5元後得到結果 8元
2、接者我先寫些測試的case 做為將來測試使用,例如
Actionscript:
-
var money2:Money = new Money( pounds2, pence2 );
-
var money3:Money = money.addMoney( money2 )
-
assertEquals( "Pounds should be 6", 6, money3.pounds );
3、然後開始寫 Money.addMoney() 這支method:function addMoney(){....}
但由於我已經知道將來會怎麼測試它,因此在寫的過程中就會特別留意傳入的參數與回傳的資料型態等細節要符合這個測試的期盼。
在 test-driven 的開發手法下,工程師寫程式是為了能百分之百通過 test case,因此在整個開發過程中就有了明確的依歸,只要test case有要求,就要在程式碼裏面完成(而且一定要完成),而 test case 沒提到的事,就沒有那麼高的priority可以丟一邊先不管,因此只要 test case 寫的夠週全,將來成品就一定可用。
另一方面,在寫 test case的過程中,工程師也會有機會先想清楚整個過程,有點類似 forsee/preview 將來程式完成的樣子,然後根據他在腦子中的觀察,去寫下所有功能的 test case,這很像是讓建築師在還沒動手蓋房子前,就在腦中冥想出未來成屋的樣子,然後照者在腦中看到的畫面去建這棟房子;這與傳統先動手蓋房子等到落成那天才能看到全貌是完全不一樣的兩回事。
最後再仔細想想,反正不論早晚都是要寫 test case (當然如果你壓根就沒打算做 testing那就另當別論),如果早寫可以帶來這些額外的好處,而晚寫卻要面臨種種風險,任何聰明快樂又有遠見的工程師應該都知道該怎麼選吧?
而 test-driven正巧也是近年來漸成主流的 agile development 重心之一,其中最為人所知的方法論就是 eXtreme Programmg (XP編程),當然 agile development 是個大題目,值得另外撰文聊聊,但這裏的重點只有一個:越來越多的工程師在經歷了幾十年的專案開發歲月後,終於發現先寫 test case帶來的效益是何其之大。
現在flash coders也有了 asUnit 3這個重量級的協力工具,要怎麼發揮它的妙用就看個人囉
note: 寫完這篇心中已經浮起另一個題目 > toward an agile flash development 聽起來還挺炫的吧?(只是有沒有時間寫就看老天了)
| by admin
目前 asUnit的最新版是 asUnit 3.0.1 alpha,據兩位負責人說這是多年以來最大的改版,完全使用 actionscirpt 3 語法,並且忠實的照者 JUnit 去刻出一樣的功能,因此對大部份熟悉 JUnit使用方式的工程師來說,只要記得把 type 改成放後面並加上 : 就可以直接開工了。
下面簡單說明一下 asUnit 3的用法。
假設你有一個叫做 Money的class,它的功能是用來加減運算金額的數目
(note:這個程式是從 as2unit裏面借來的,我將它改寫成AS3 語法並修掉一些錯誤以通過測試)
Actionscript:
-
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會不會通過,可能會用類似下面的程式:
Actionscript:
-
var m:Money = new Money(5,10);
-
m.addMoney(new Money(2,10));
-
trace(m)
然後看結果是不是如預期中的金額。
這很明顯的,這樣做非常沒有效率,而且當class結構越長越大時,就很難維護這些test code。
因此比較好的做法是寫一個獨立的 test class,像這樣:
Actionscript:
-
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集合起來一次執行,請看範例:
Actionscript:
-
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。
測試語法如下:
Actionscript:
-
mt:MyTestSuite = new MyTestSuite();
-
mt.run();
不過這樣做有個小缺點,就是除非執行過程中有發生錯誤,才會在eclipse的console中顯示錯誤訊息,但如果全部通過的話就完全不會顯示任何資訊。
為此asUnit很貼心的提供了兩種選擇,第一個是用 flex 畫出來的測試介面,使用方法如下:
Actionscript:
-
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裏面執行,但由於我不需要這種玩意所以抓回來後從來沒執行過。
| by admin
unit test在專業的軟體開發過程中一直是非常非常重要的一環,透過一個有系統的方式來檢測程式碼的正確度可說是軟體開發最低限度的要求。
但到目前為止,10 個flash coders裏大概有 11 個都是用唯一的一種方式來做所謂的 test : CTRL-Enter,也就是 test movie來執行電影,然後看看output panel裏有無出現錯誤。(呃,如果你不屬於這11個,並且已經在用某種 unit test framework,那請直接跳過這篇文章去做更有意義的事,例如補個眠)
傳統用 test movie做測試對付小型的專案還行有餘力,但當案子發展的越來越大,並且完全走向 class (OO)導向的開發方式時,這種做法就顯的費時費力且不切實際,另一方面,這種測試方法往往要等UI好了才比較能整合起來測試,但往往這時有些根本的錯誤已經種的太深很難再改了。
在java的世界裏,這個問題很早就獲得了解決,他們可以靠一個叫 JUnit的 testing framework 來自動化所有的測試工作,只要簡單的設定與編輯,就可以完整的測試所有class中的每一個method運作是否正常,並且更重要的是,這些test class可以做為日後改版或 refactoring時重要依據,例如每次改完程式碼或refactor一大段code blcok, 就重跑一次test,只要測試能過,就代表剛才做的改變沒問題。
在Flash的世界中其實也有類似JUnit的東西,幾個檯面上比較知名的(其實是也就只有這幾個啦)
-as2unit:
這是英國的 iteration:two顧問公司所發展的test framework,,as2unit的基礎架構是照者 JUnit翻版而來,但它只保留了幾個重要的部份,因此功能上不是非常完整。btw, 這家公司日前才剛被macromedia收購成為 Macromedia Europe Consulting (MEC)。
-as2lib:
這是最早期出現的一個全能型 library,裏面也包含了一個小型的 unit test library,但由於太冷門一直無法成為主流。
-flex unit:
這也是 iteration:two推出的project,但主要是針對 flex 做 unit test,只是隨者 flex 2的出現(與伴隨而來的大改良),這個project結束的日子應該不遠了。
而本文要介紹的,則是由macromedia官方支援(金援)發展的正宗JUnit flash-port版:
AsUnit
asUnit也是一個open source的testing framework, 並且也存了在相當長一段時間,但由於一年前macromedia正式加入這個proejct,並且提供足夠的經費供他們做研發,因此他們順利的成為第一個支援Actionscript 3 的 testing framework。
| by admin
這標題聽起來很聳動,不過對我而言是挺有效。
經過這幾年的實驗,我發現聽的音樂類型對coding順暢度有很正面的影響,其中以 jazz 最有效,而 jazz 中又以鋼琴獨奏或trio的型式效果最好。
過去幾年凡是要做複雜的coding工作時,通常不二的選擇就是 Keith Jarret

Keith Jarret的獨奏鋼琴聽久了似乎可以安定腦波,有助延伸思路或預見許多原本不會發現的潛在地雷(bug),以往許多神奇的架構規畫或implementation就是這樣不經意想出來的。
今天又重整了一次 iTune 的 folder,順便列一下常聽的 Keith Jarret 專輯:
At The Blue Note I Friday, June 3rd 1994 1st Set
At The Blue Note II Friday June 3rd 1994 2nd Set
At The Blue Note III Saturday, June 4th 1994 1st Set
At The Blue Note IV Saturday, June 4th 1994 2nd Set
At The Blue Note V Sunday, June 5th 1994 1st Set
At The Blue Note VI Sunday, June 5th 1994 2nd Set
Bye Bye Blackbird
J.S.Bach Goldberg Variations
Standards Live Vol.1
Standards Live Vol.2
Sun Bear Concerts - Encores
Sun Bear Concerts - Kyoto
Sun Bear Concerts - Nagoya
Sun Bear concerts - Osaka
Sun Bear Concerts - Tokyo
Sun Bear Concerts Piano Solo- Sapporo
The Koln Concert
The Melody At Night, With You
Up For It
另外更早之前也常聽 Thelonious Monk 的東西,也是有者神奇安定功效的音樂,這兩年則又發現另一個天才型的樂手 Brad Melhdau (這是在紐約時某東村小唱片行老爺爺硬塞給我的片子,結果一聽就上癮),可惜他還太年輕專輯沒幾張,希望未來能活久一點就可以源源不絕的出片...
嗯 這篇就放「軟體工程」裏吧,畢竟大腦正常運作是軟體工程內最重要的一環啊 
| by admin
公司網站

感謝yaya提供這個網站。(btw, 順便謝謝幫我測試原來右下角的留言版真的可以用 :D)
這是一個法國公司(一人?)做的仿 flexstore EC solution, 純手工用flash 硬拼出來。
晚上花了點時間玩了demo site順便看了一下程式碼,是用as1 + flash remoting v1 + amfphp完成的。
整個程式架構基本上是恐怖的spaghetti code,一堆的function分散在不同層次的movieclip,然後有大量的 onClipEvent()去觸發不同層級的事件。
另外主UI 上的三大塊panel也是用movieclip畫好3個keyframe擺上去的,這代表它絕不可能像flexstore裏的window元件可真正放大/縮小,而只能透過 onPress去觸發 gotoAndStop()變換到不同大小。
總之,整個程式架構跟寫法就跟自殺並無二致,恐怕再過三個月連當初寫的工程師都不認得裏面在做什麼,更別提將來其它人要接手維護或擴充功能時會面臨的挑戰。
(這也就是市場上為何總是有公司在找「維護合約」的廠商,而大部份有sense的廠商也都不願碰這種半路殺出的案子,因為誰也不願接手幫人家收拾善後,去修改一堆亂到不行的程式碼最後搞的自已也深陷泥沼動彈不得)
當然這並不是說不用物件導向或as2或Pattern/CBD寫程式就一定該死,國外也有不少高人寫的一手漂亮的as1(例如 flashmyadmin的darren就是近乎神人的例子),重點是在於系統設計與架構的高明與否,以及寫程式的人本身對功能、責任區分的概念(例如MVC的每一塊意義與彼此溝通的方式)是否夠清楚,簡單一句話就是程式設計師的功力與觀念,決定了他能創作的境界高低。
這也正好呼應了joel 之前的說法,花貴的錢請最好的工程師,換來的收穫絕對比請一群二流的工程師高許多,因為 they can never hit the high note, they just don't have it.
舉一個簡單的實例。
有位朋友,姑且稱作X桑,剛回台灣工作,幫某大銀行做data mining;他的任務就是從該金控龐大的資料庫中撈出可再撥一層皮的肥羊,呃,我是說可供幾百個業務電話行銷的尊貴客戶,而有趣也是令人驚訝的地方在於,該公司的資料庫中,光日期一欄,就可以撈出千百種不同的格式,例如以 民國 93 年 1 月1 日為例,裏面有的格式就包含:
-0930101
-930101
-20040101
-九三0101
因此,到最後這位有為青年X桑主要的工作就是用sql function把這幾十種不同的日期格式統一換回西元日期(有興趣可以用MS SQL試試看這件事)
其它諸如此類不可思議的東西還有千百種。例如某卷商資料庫中,居然可以撈出下單日期比開戶日期早的資料(請問單子要下到那個戶頭去?)
但這是一家全國幾萬名從業員的大金控,裏面的資訊部門恐怕比大部份中小型資訊公司總人數都多,為何還會出現這種幾近可笑的錯誤?
答案很簡單。二萬八。
這是一個大學畢業剛進去寫程式的人起薪,而天兵日期格式可能就是在某年七、八月畢業季新人到職後寫下去的,一套系統經過幾年新人的反覆折騰,就成為今天這個樣子,終於有一天它會龐大到完全無法修改與維護,然後就是爆炸的時刻,接下來104上面就會出現一個「金融系統維護合約」....
我相信joel會提出「高等人才無價論」必然也是親眼看過二流工程師幹的好事與結果,才會有感而發~
這實在值得業主、資訊公司老闆跟工程師深思啊~
| by admin
Previous Posts