最近的三張塗鴨
一張是紀念需要打領帶上班的日子,或者說懷念那些上班時間可以自由調整的日子
一張則是朋友的作品在上面連載,仿其主角畫了個cute版,不過因為沒時間完成,完成度欠佳
一張則是上班時無聊畫的
—–
視覺化UML設計開發實務
作者:孫惠民
出版社:旗標出版
出版日期:2004 年 02 月 25 日
這本書是我去年在Book7購書時用點數換的,最近工作上除了要寫個程式,更多的時候就要思考怎麼樣才是一個好的軟體架構和弄清楚公司中的系統架構,用<abbr title="Unified Modeling Language">UML</abbr>來將一些資訊作整理可能是不錯的方式,所以就隨手拿了幾本書來看,這本書就是其中的一本。
基本上,這本書大部份的篇幅都花在如何使用Visual Paradigm這套工具來繪製UML圖形,偏重於Visual Paradigm這套工具的使用和操作。每章的開頭有整理出本章的重點和注意事項,這麼做不錯,不過當你翻頁過去,立刻又會看到「大同小異」的話……,讓人有種!@#$%%的感覺,自我成長單元的立意佳,可惜題目沒什麼用。書中很多的小例子充斥,但都是過於簡單的例子,讓人覺得太過於基本,而且不需要/可縮減的圖形太多,圖形也缺乏處理。
第二章在教讀者怎麼樣去畫出在第一章中的圖形,可見作者的物件概念不錯(可重用性),也很聰明(一魚多吃),至於後面的對階層計算、九九乘法表Class Diagram,讓我Orz到不行,實在不想講,心中暗自覺得:「這有什麼值得用UML畫的?」
另外,作者在講述範例時,是以直接分析好的文字,直接要讀者們跟著畫UML圖形,問題是:我不需要你說了:A是由B繼承而來,B與C有關連,然後我去畫它的UML圖形,我需要的是一個案例、一個場景的描述,然後怎麼樣抽絲撥繭,最後才畫出一個合理的UML圖形,而且這本書所介紹的UML圖形應該是UML 1.4的,最新的已經是UML 2.x了。最後整合運用時,講解了進銷存、會計系統,不過又將系統太過於簡化,雖然我是覺得內容於章節名稱不符。
但是這本書還不致於一無可取,它所介紹的Visual Paradigm可就是好物了,在網路上稍微看了一下,它是套由香港公司、中國人寫的UML建模工具,最近也得了不少獎,除了可即時正向產生C#/Java程式碼、可以結合VISIO、加入一些VISIO的圖形之外,還有檢核你畫的UML是否正確的功能,所以如果要我說:這本書就是「雞肋型」的電腦書,食之無味,棄之可惜啊~~。
工欲善其事,必先利其器
所以我最近上網找了些UML的相關工具,連結如下,若有別的,還請各位補充 😀
- tablet uml:給tablet PC使用
- someone’s UML collections
- Poseidon for uml
- Visual Paradigm:據說是中國人開發的,2006年得了不少獎
- ArgoUML
- JUDE:好用,最近剛更新到3.0
- Sequence Diagram Editor
- MDA tool
- Rational Rose:IBM收購了Rational,UML標準工具,不過介面稍差
- Borland Together Architecture:Borland收購了Together推出的工具,有.NET的plugin版和JBuilder版,有別的小差異版本(Borland Together Designer)
- SmartDraw:像是Visio的工具
- MagicDraw UML:OSX上UML工具的首選
- BlueJ (a java IDE):澳洲某大學開發的工具,簡單易用,最近NetBeans有結合BlueJ的版本
- Visio2003:微軟的工具,善用其隱藏功能可變成訂定流程的工具
- Altova UModel
- Optimal Trace’s use cases and UML
- Flash UML工具介紹
- gModeler
- XMI UML Converter for Macromedia Flash ActionScript 2
- UMLGraph – Declarative Drawing of UML Diagrams
莫名的回想
最近下班後除了去游泳外,就是看電視劇「白色巨塔」了,其中女主角關欣是由張鈞甯扮演,從她演出「赴宴」的時候我就覺得她蠻漂亮的,不過,我在想,我可能因為她而突然莫名其妙地回想起一個人:他名叫張鈞棋(大概是只差一個字的關係),是我小學一年級的同學,只記得那時候他家在我家隔壁條巷子的最後一間,也不知道為什麼和他特別聊的來,小時候我們倆都很有實驗精神,記得那時學校上課上到溫度的時候,二個人回家後約在他家把冰箱上層的冰刨下來,用一根長長的溫度計量溫度,量到了零度C,就好像驗證了什麼真理一樣的高興,後來不小心把溫度計弄斷了,二個人還好像做了什麼壞事般,趕緊拿了掃帚在掃地,還記得他家裡放的圖畫紙,一次就是一大疊,和一般人要用時才去文具行買個一、二張不同,我們倆就這樣熟絡地玩了一年,到了小學二年級,他突然要轉學了,只記得那時他的爸爸還特別拿了一張寫有他們新家的電話給我,要我有時間和他們常連絡,只是我後來不小心把那張紙弄丟了,於是就從此斷了他的消息了。
不知道是為了什麼,在二十多年後突然想起這件事。
另外,就是和朋友L說了一件高中時的事,結果L回信說他也有相同的記憶。
和老友有著共同的回憶,其實是蠻值得珍惜的一件事,尤其是經過了十多年之後……
只是,最近的記憶老是跳回很久之前,真不知大腦在想些什麼,大概是在自動地磁碟重整吧。
—–
Pragmatic Unit Testing in C# with NUnit
作者:Andrew Hunt, David Thomas
出版日期:2004年五月
很薄的一本書,才146頁,最近花了一個禮拜抽空把它看完,不過我讀的時候,發現2006年八月一日又有新版了,新版據說是多了以下的材料:
- Updated for NUnit 2.4 (.NET 2.0 and Visual Studio 2005)
- More assert methods
- New String and Collection assertion support
- Better support for multiple-platform development
- Higher-level setup and teardown fixtures
- Whole new chapter on extending NUnit
- and more!
這本書寫的不錯,蠻簡單易懂的,在 Amazon有五顆星的評價。本書的程式碼範例在Source Code of Book: Pragmatic Unit Testing in C# with NUnit,另外,有幾章都有讓你練習的題目,且在書本最後有附解答,非常適合自學的人使用。
以下是我的筆記:
<h2>第一章 簡介</h2>
第一章在講解為什麼需要Unit Testing,也反駁了一些不用Unit Test的人,更給了個各大語言Unit Test Framework的網址:http://www.xprogramming.com/software.htm,另外,也講了一個重點「要將執行的測試case依時間分類,執行一次很長的,就可能一天或一週做一次,至於時間短的,就天天做、常常做。」
NUnit有三種型式:
- 自己的GUI,可以獨立執行
- command type的,可以在每次build之後,緊接著做單元測試
- plugin的
<h2>第二章 你的第一個單元測試(Unit Test)</h2>
第二章舉了一個找最大值的超簡單範例,用來說明Unit Test的重要性及如何以NUnit來做TDD(Test Driven Development)。
<h2>第三章 用NUnit寫測試</h2>
第三章則是教你寫一個Test,並說明如何以Test Suite來組織你的Test Fixture。讓你可以輕鬆地一次測試數個不同的Test Fixtures。不過Test Suite仍不適合每日的定期測試,NUnit還有另一個機制–Categories,Categories可以讓你將你的測試方法分類,然後你可一次選擇數個categories來執行你要的測試,你可藉由categories來區分那些短時間就能跑完測試的test cases及那些需要長時間才能執行完的test cases,然後將長時間的設定只在夜間執行。categories可由屬性(attribute)來指定。
using NUnit.Framework;
using Nunit.Core;[TestFixture]
public class TestShortestPath{
[Test]
[Category("Short")]
public void Use5Cities(){
TSP tsp = new TSP(); //讀取default cities
Assert.AreEqual(140, tsp.ShortestPath(5));
}[Test, Category("Short")] //也可以這麼指定
public void Use10Cities(){
TSP tsp = new TSP(); //讀取default cities
Assert.AreEqual(586, tsp.ShortestPath(10));
}//這會花比較多的時間
[Test, Category("Longt")] //也可以這麼指定
public void Use50Cities(){
TSP tsp = new TSP(); //讀取default cities
Assert.AreEqual(2300, tsp.ShortestPath(50));
}
}
也可以mark整個class設為一個category
using NUnit.Framework;
using Nunit.Core;[TestFixture, Category("Longt"]
public class TestShortestPath{
[Test]
public void Use50Cities(){
TSP tsp = new TSP(); //讀取default cities
Assert.AreEqual(2300, tsp.ShortestPath(50));
}
[Test]
public void Use150Cities(){
TSP tsp = new TSP(); //讀取default cities
Assert.AreEqual(5357, tsp.ShortestPath(150));
}
[Test]
public void Use100Cities(){
TSP tsp = new TSP(); //讀取default cities
Assert.AreEqual(4675, tsp.ShortestPath(100));
}
}
利用[Setup]和[TearDown]來獨立測試
[SetUp]
public void MySetup(){
…
}
[TearDown]
public void MyTearDown(){
…
}
MySetup會在[Test] method之前被執行,而標示為[TearDown]的MyTearDown()方法會在[Test]的method之後被執行
所以是:[SetUp]->[Test]->[TearDown]->[SetUp]->[Test]->[TearDown]…
另外還有per-class的Setup和TearDown,用法的關鍵字是:
[TestFixtureSetUp]和[TestFixtureTearDown]
呼叫順序是:[TestFixtureSetUp]->[SetUp]->[Test]->[TearDown]->[SetUp]->[Test]->[TearDown]…->[TestFixtureTearDown]
注意:
- 你可以在同一個class中用per-class和per-test方法
- 也可以寫客製的Assert-Style方法
- 對於Expected Exceptions,你應該每個Exception都測,看他是否真的會丟出來
期待它正如期望的會丟出一個Exception:
[TestFixture]
public class TestException{
[Test, ExceptedException(typeof(ArgumentException))]
public void TestForException(){
whitePages.ImportList(null); //如果沒丟出ArgumentException,那麼Test為failed
//應該不會到這裡
}
*對於un-expected exceptions,NUnit會報告整個stack,下到bug本身
*可暫時忽略的Tests:用[Ignore],在NUnit GUI中會以黃色出現
[Test, Ignore("Not ready to test this yet")]
public void TestSomething(){
xxx xxx xxxxxxxxxx;
}
<h2>第四章 你要測試什麼?</h2>
口訣:RIGHT-BICEP
RIGHT: 正確性
B:Boundary condition
I:Inverse relationship:
C:Cross-Check:可用效率較差、前一版本的方法來測試數字的正確性,交叉驗證
E:Error condition:強制Error發生
P:Performance characteristics within bounds:要測試的不是數值,而是在loading 大時,能否維持performance curve
<h2>第五章 考慮邊際條件(Boundary condition)</h2>
口訣:CORRECT
C:Conformance:與所期待的一致
O:Ordering:順序是否正確,或是正如所需的無次序。以點菜程式的上菜次序為例。
R:Range:值是否在合理的範圍之內,是否符合domain的要求,index的範圍有被詳加測試嗎?數目有符合嗎?…
R:Reference:code是否參考到外部未受管控的部份?
E:Existence: 值存在嗎?(非null、非0、在集合中存在……)
C:Cardinality:與Existence相關,不過更想知道數量是否相符。有足夠的數目嗎?(依0-1-n Rule作測試,其中 n可隨demand修改)
T:Time:每件事是否依先後次序發生?用去的時間正確嗎、與牆上時鐘的時間一致嗎?有及時發生嗎?同時間發生的事件
<h2>第六章 使用Mock物件</h2>
Q: 如果method與難以掌控的事物(e.g., 網路、資料庫、M$當日股價)相依,那要怎麼測試?
A: 用Mock Object 來騙程式!
使用Mock Object的三大步驟:
1. 使用interface來描述object
2. 實作介面(interface)以產生真正的程式碼(production code)
3. 實作在mock object中的interface以供測試
DotNetMock是一套用來建立Mock的Framework NUnit 2.2之後有內建的mock objects
Q:當你要測某個使用既存interface的東西,又沒有預先寫好的mock objects,且此interface有一堆accessors和methods,但如果你只需要測試其中一、二個methods呢?
A:用Dynamic Mock Objects!
有二套有Dynamic Mock Objects的Framework
<ui>
Q:何時不要用Mock?
A:因為寫mock也會花費專案的時間,有時經過refactoring後就不需mock了,所以要好好想想,是否有這個需要。
P91 舉了一個我看了很久還有點不是很懂的例子……
<h2>第七章 良好測試的性質</h2>
Unit Test如果沒有好好寫,反而要花很多時間在改Test code,沒花在production code上,造成本末倒置!
良好的測試的特性是A-TRIP
A: Automatic:
可以自動地被呼叫和自動地檢視結果是否正確
別引入會破壞自動模式的Test(像是真實世界的資料庫和網路連線有可能會破壞自動測試,這時要利用mock object來隔離它們,維持自動Test)
Cruise Control 可用來維持持續的建置和測試
T: Through(透徹的):
一個極端是:測試任何可能出錯的地方;另一個是:只測試最可能發生錯的地方--邊際條件、缺漏或格式不對的資料……等。
NCover:可讓你看你的程式碼中有多少是真正地被執行過了。
R: Repeatable(可重覆的):
可重覆執行且不受任何外在環境(含開發者)的影響,每次都能產生相同的測試結果
I: Independent:
寫測試時,記得一次只測一件事,要寫得集中些。
你可以寫數個方法來測一個部份,但要能被追蹤,也就是:出錯時要很快地找到bug在哪裡
independent也代表,沒有測試是依賴於其它的測試之上。
也就是說,每個Test可以以任何次序被執行,善用per-test/per-class的 setup和teardown method的機制
“Every test should be an island."
P: Professional:
測試碼必須寫得和Production/real code一樣專業
有時測試碼會比production code更多,一般是幾乎一樣多!
Q:如何修正bug?
1. 辨識出bug
2. 為bug寫一支會失敗的測試,來驗證bug是存在的
3. 修改程式碼,使得測試可通過
4. 驗證所有的test仍全都能通過
捉到bug時要思考:同樣的問題是否會發生在其它的地方?
<h2>第八章 於專案上測試(Test on a Project)</h2>
Q:遇到private method時怎麼測?
A:書上寫的是該破壞其封裝時就破壞,讓private變成public,我個人是覺得寫一個public的Test method在class裡,再由外部去叫那支程式
Q:要在專案中哪裡放測試碼?
A:有二個方式
<h3>第一個方式:和對應的class放同一個目錄</h3>
例: com.pragprog.wibble.Account
的測試碼就選在:
com.pragprog.wibble.TestAccount
這樣有一個優點:TestAccount可以存取Account的internal和protected internal member variables和methods(指C#)
也有個缺點是:測試嗎弄亂了production code的目錄
<h3>第二個方式:放在分開的組件(separate assemblies)裡</h3>
優點是:可乾淨地分開production code和test code
缺點是:test現在在不同的組件(assembly)裡,你不能存取internal和protected internal變數,除非你的test code使用了一個與曝露了(exposed)所需的變數的production code相同的subclass。
例如,你想測的class如下:
namespace FacilitesManagement{
public class Pool{
protected Date lastCleaned;
public void xxxx xx}
xxx xxx xxxx;
}
…
}
}
那麼你的測試碼要去expose那個protected變數:
using namespace FacilitesManagement;
namespace FacilitesManagementTesting{
public class PoolForTesting: Pool{
public Date LastCleaned{
get {return lastCleaned; }
}
}
}
這樣一來,可以用PoolForTesting來測試
無論選了那種方式,重點是要一致!!
*過了Unit Test,才能check in 到version control system!
“all tests pass all the time."
P105. checkin後,造成不能fully tested 或自動build的程式碼中可含一行Unit Test相關的訊息來「提醒」其它的團隊成員。
jiing:記得在《Joel on software》中有說過,某人新check in的程式碼若造成build不出來,那麼那個人就要接下build package的工作。
<h3>測試的頻率</h3>
- 新method:本地的unit test
- 要修正bug時:執行tests來讓bug顯見,修正,然後重新執行unit tests
- 任何成功的編譯:執行本地的unit test
- 每個check in到version control system的module:執行所有的模組或系統的unit tests
- 持續地測試:至少要有一台專門地、自動地執行build和test的機器,依專案大小可調整,畢竟,介於自動建置間的時間愈長,介於製造問題和辨識問題間的回饋時間就愈長。有台真的建置機器找問題會比真的開發者找得快。
<h3>測試古早遺留下來的程式碼</h3>
Q:如何測試那些沒有unit test的程式?
A:這根據程式碼目前的狀態而定,如果程式碼已經被良好地構建且模組化了,那麼你可以輕鬆地加入unit test。如果是一團爛泥,為了unit test,那可能免不了大量的改寫。如果沒有完美地被構建(perfectly factored),但有足夠的模組化,那麼還是可以加入unit test。
實務上也不用對既存的程式碼加入測試於所有可能發生錯誤,你只要先加到最可能發生的地方即可,以得到較佳的投資報酬。。
*當處理古早程式碼時,迴歸測試顯得更為重要。
任何出現二次bug的issue,在當週週末前要生出unit test code
*如果要code review的話,Test Code和Production code一樣都需要被review
<h2>第九章 設計上的事宜(Design Issues)</h2>
這一章講解了設計上要注意的事項,用一個簡單的食譜成份查詢的程式來說明,除了一般class架構上的設計之外,還有一個就是要能不用GUI也能執行測試。
Unit Test提供數個機會來改進程式碼的設計和架構
<h3>為可測性(testability)考慮設計:</h3>
“Write Shy Code."
— “The Pragmatic Programmer: From Journeyman to Master, Andrew Hunt and David Thomas"
寫程式時就要思考如何去測試它,如果覺得很難測或是測試碼會很醜,那麼這是個警訊!設計可能必須被修正。
<h3>重構!</h3>
<h3>藉由定義class invariants來釐清設計</h3>
一個class invariant是一個/或一堆 assertion
通過invariant才代表你不是因為幸運才通過測試的
資料的一致性也是invariant(即使其表現方法不同)
<h3>用測試驅動設計(Test Driven Design)的方式來改進interface</h3>
先寫測試,再寫程式–測試先行!
用使用者的角度寫測試
從不同的角度來看,或許能改進設計
<h3>負責建立和局部驗證</h3>
- 當由你負責從外部輸入資料的正確性時,要戒慎恐懼地做!
- 不是你負責時,就不用檢查了,要信任別人!
<h2>附錄A</h2>
講了一些重要觀念或常人的誤解/迷思:
- Unit Test壞了,程式碼就算是壞的
- unit test優於smoke test,smoke test有時只是讓你暫時以為ok了,要注意smoke 型式的測試
- 所有的test必須所有的機器上都通過,否則程式碼就算是壞的
- 浮點運算中,看起來一樣,未必是相同,可能的差異比能顯示的更小
- 花太久時間測試
- 單元測試必須被快速地執行,會執行太久的單元測試要被挑出成(可能)一天執行一回,但不能讓它們變成永不執行測試
- *測試只在某些機器上失敗、bug會間歇地出現:一定要讓bug重現!
jiing: 最後一項的二個bug我都遇過,軟硬體夾雜的問題最慘……
<h2>相關連結:</h2>
Cruise Control .NET:自動連續測試、建置的server
DotNetMock:是個.NET的Mock Object repository
NCover:用來測試程式真正被執行過的比例
NMock: Dynamic mock-object library for .NET
NUnit:.NET的單元測試
Visual Studio 2005的NUnit plugin
xUnit:各種語言、環境的單元測試Framework
NAnt
本書作者之一:Andrew Hunt的blog
Andrew Hunt出新書接受perlcast的訪問
—–
不敗地球人必修的十二學分
<h3>值得花些時間聽聽!</h3>
最近利用上下班通勤的時間,斷斷續續地花了近二週,終於用向老姐借來的iPod shuffle把王文華和趙少康合錄的「不敗地球人必修的十二學分」聽完了,這套有聲書是「史丹福的銀色子彈」的加強版,談及更多書上可能因篇幅限制所無法提及的,甚至是二個講者在對談中所突然蹦出的想法,除了像是重溫了史丹福的銀色子彈一書外,也有一些真的要經驗過的人才知道的道理,當然,還有很多讓我在公車上抿嘴微笑的趣談,讓我似乎又注入了少許的動力,可以繼續前進!
—–
-
最近的
-
鏈結
-
文章存檔
-
分類
-
RSS
Entries RSS
Comments RSS