2009年3月10日 星期二

TDD 推廣:相關工具

前篇,這篇說明我近兩週開發過程中選擇工具的心得。

開發環境

我採用 Eclipse,配合 Eclipse 的 refactoring tool,大幅加快重構的速度。人都有惰性,好工具讓我們更願意重構,而且降低重構過程除錯的風險。對照之前我自己寫 C++ 和 Python 的經驗,現在我更常做 rename variable/method、change method signature 之類的操作。

Unit Test

經過評估後,我決定用 JUnix 4.x。JUnit 4.x 改用 annotation 的方式表示 test method,可以去除必須繼承 TestCase 的限制。如此一來 test method 命名彈性更大,而且也可以直接在 class 裡加 test method 測 private method,解決因 private 不方便測試的困擾。不過我不確定這種作法是否正確,仍需多點經驗判斷。其它 JUnix 4.x 的好處可以參照《An early look at JUnit 4》

關於 unit test 的技巧, ThoughtWorks 有出相關的書:《xUnit Test Patterns: Refactoring Test Cod》。有機會再去書店翻看看。

Mock lib

關於 mock 的知識可以參見 Martin Fowler 的《Mocks Aren’t Stubs》,解釋得鞭闢入理,除介紹 mock 外,更進一步指出用與不用 mock,其實測試思維是截然不同的(確認物件行為或確認物件狀態),有機會的話再對此另寫心得。文中的範例程式有點過時(畢竟是舊文章),現在 mock lib 的用法更方便一些。Java 的 mock lib 有許多選擇,最後我選用 EasyMockZ。除了好用外,主要是因為 Python 的 Mox 是從 EasyMock 來的,這樣寫 Python 時可以花較少心力學 Mox。

2012-08-05 更新: 我現在改用Mockito了,更為簡單易用 。

Database unit testing

若只是用到簡單的 database 操作,可以用 EasyMock 處理,。測試前準備好 mock connection、mock statment、mock resutSet 即可。一方面是初學 mock 的緣故,另一方面也是 database 相關操作太瑣碎,我花了一整個下午才用 EasyMock 完成測試程式並寫好對應的功能。事後修改挺複雜的,比方說我程式裡補了 close(),mock statement/connection 也要記得加。感覺不是理想的作法,這方面經驗尚淺,需要多點實戰。

若要測得更深更全面一些,測試對 DBMS 本身的操作( insert / delete / update)的話,用 DBUnit 會方便許多。DBUnit 的基本精神是幫測試程式準備好已知狀態的資料庫,以及比對兩個資料庫是否相等。它的核心功能是將資料庫內容和 XML 檔案互轉。所以,先建好一個資料庫,透過 DBUnit 將整個資料庫存成一個 XML 檔,日後隨時都能用該 XML 檔還原回原樣。

對測試程式而言,執行速度是非常重要的,執行速度快才能反覆地執行多次,才方便反覆開發、重構以及整合測試。所以我改用 SQLite 做為測試用的資料庫,真正的產品再用 MySQL 之類的 DBMS。SQLite 的好處是支援 SQL92 的語法,整個資料庫只要一個檔案即可。如此一來只需要讀寫本機檔案,省去網路連線的負擔,也方便建置測試環境。

由於使用 DBUnit 前得先準備好資料庫才行,我得先從既有的 MySQL database 建出同樣 schema 的 SQLite database,才能用 DBUnit 做後續的操作。原本打算寫個程式讀出 MySQL database schema 再建出 SQLite database schema。但兩者建 table 語法差太多,無法直接套用。最後我是利用 DBUnit 產生的 XML 檔,寫程式從 XML 檔中讀出 table 和 column 名稱,再建出簡單的 SQL 指令來建出 SQLite database。如此一來,每次自動測試前我先用 DBUnit 將 SQLite database 填入備好的資料,就能快速地重覆在同樣的狀態下測試資料庫操作的程式碼。待有更多相關經驗後,再針對此議題寫篇心得。

相關閱讀

沒有留言:

張貼留言