一、簡介
目前針對測試驅動開發技術的研究在國內看來還少得可憐,估計這主要是國內的軟體開發實際所致(急功近利型頗多)。所以,針對目前比較優秀的測試架構以及類比架構的介紹也不多見。鑒於此,我想借這篇短文,對目前.NET平台上最新出爐的類比對象架構—Moq作一簡介。Moq的發明者聲稱,較之於其他的類比對象架構(例如Rhino Mocks和TypeMock Isolator),這個架構更易於學習和使用。
具體來看,Moq架構中充分利用了VB.NET和C#語言的最新特徵,例如lambda運算式與泛型的概念。因此,當你使用Moq建立類比對象時,你可以使用lambda運算式來描述你想要類比的方法與屬性等。由於提供了對於最新的lambda運算式的支援,Moq得以能夠提供一種格外清晰的文法形式來描述期望值、參數約束和傳回值等。
根據Moq的作者的說法,你可以把“Moq”發音為“Mock-You”或者乾脆與“Mock”一致。名稱“Moq”源於Mock和Linq的組合。既然Moq使用的是lambda運算式而不是Linq運算式,所以名字“Mambda”似乎更為準確一些。
Moq架構的維護者為Daniel Cazzulino。你可以閱讀Daniel Cazzuiono關於Moq的部落格入口:
http://www.clariusconsulting.net/blogs/kzu/archive/category/1062.aspx。
本文中我們集中討論的是Moq的2.5版本,其實這並不是最新的(例如下文圖中給出的2.5.3版本下載後的檔案名稱字),但是基本代表了這個架構的最新特徵。
二、背景與爭論
關於類比架構的使用,一直以來存在一些爭論。目前在.NET平台上主要存在三個流行的Mock架構,它們分別是:Typemock Isolator,Rhino Mocks和Moq。其中,TypeMock Isolator因其功能過於強大而受到批評;相反地,Moq也因過於簡單也受到同樣的批評。為什麼會存在這種看似荒誕的批評呢?
一些人批評Typemock Isolator的功能過於強大。批評者認為,TypeMock Isolator可能會導致鼓勵糟糕的軟體設計,因為你有可能使你在代碼架構的設計方面產生惰性,理由是編寫可類比的代碼應該能夠迫使開發人員編寫出更良好的代碼。現在的情形是,Typemock Isolator能夠支援你類比出任何東西,甚至是你想類比的一切。因此,批評者認為,這個工具並沒有把開發人員引導到良構代碼的編寫道路上。他們甚至還打了另一個比方,說Typemock Isolator就像把一個核武器交給一個僅僅四歲的小孩使用一樣。
在Typemock Isolator被批評其功能過於強大的同時,Moq則被批評其功能過於簡單。抱怨者認為,Moq混淆了類比與代理。如果你想深入理解上述批評觀點,必須具備一定的背景知識才行。為此,你不妨參考驅動開發權威Martin Fowler曾寫過一篇標題為“Mocks Aren't Stubs”的很有影響的論文,其相關網址為:
http://martinfowler.com/articles/mocksArentStubs.html。
Fowler在上面這篇論文中對好幾組概念加以區別。首先,他區別了代理(stub)和類比(mock)。根據Fowler的看法(此處他引用了Meszaros的定義),代理對於測試期間進行的調用提供了封裝現成的答案,經常情況下,這種封裝與當前測試之外的內容是毫無關係的。相比之下,類比(Mocks)是一些提前編寫的帶有一定期望的對象,這些期望對於所進行的調用加以聲明-期望達到的結果。
根據上面這對概念的區別,Fowler又進一步對狀態校正(state verification)和行為校正(behavior. verification)加以區別。當執行狀態校正時,代理最為常用。當執行狀態校正時,你更感興趣的是測試結束某個條件是真還是假。而另一方面,當執行行為校正時,最為常用的卻是類比(Mocks)。當執行行為校正時,你更感興趣的是類比對象之間是如何互動的。例如,你想知道在另一個類比對象上調用了一個方法之後是否在某個類比對象上調用了某個特定的方法。
Fowler最後區別了傳統的測試驅動開發(classical TDD)和類比主義測試驅動開發(mockist TDD)。其實,Fowler對這兩者的區別涉及到如何進行測試和設計的根本問題。傳統的測試驅動開發者趨向於使用代理和狀態校正。根據Fowler的說法,傳統式測試驅動開發風格在於儘可能使用真正的對象,而當這種情形相當難以實現時又引入近乎兩倍的真正對象以試圖實現既定測試目的。而一個類比主義測試驅動開發者幾乎總是使用類比和行為校正方案,他們會一直針對感興趣的行為使用任何的類比對象。
一個傳統型的測試驅動程式員會使用一個類比對象架構來簡化單元測試。如果你想要測試的代碼依賴於另外其他的對象,那麼,你可以為當前不太方便的對象快速建立一個代理(stub),從而繼續進行你的單元測試工作。因此,從一個傳統型的測試驅動程式員角度來看,一個類比對象架構的主要意義正在於此。
相比之下,類比主義測試驅動開發者持有完全不同的觀點。他們認為,應用程式的設計應該受你期望對象在程式中互動的方式的驅動。因此,他們使用類比對象來類比實現最終的應用程式。因此,在測試期間,他們會類比所有的東西。
Moq因其沒有尊重傳統型測試驅動開發者和習慣於使用類比對象進行測試驅動開發的開發人員而受到指責。Moq使得很容易地建立代理(stubs)而不是類比。這或者是一件好事,也可能是一件糟糕的事情,具體要依賴於你使用的類比對象架構的目標。
Daniel Cazzulino,作為Moq架構的主要建立者,無可辯解地是一位傳統型測試驅動開發者。在Daniel Cazzulino和Ayende (Rhino Mocks架構的作者)之間曾經有一次很有意思的意見交流,此網址為:
http://www.ayende.com/Blog/archive/2007/12/19/Moq-Mocking-in-C-3.0.aspx
Daniel Cazzulino認為,大多數的開發人員,如果他們使用了測試驅動開發的話,並不會區別什麼是傳統的測試驅動開發(classical TDD)和什麼是類比主義測試驅動開發(mockist TDD)。事實上,這兩者之間的區別並不像Martin Fowler所描述的那樣清晰分明。為此,Daniel Cazzulino撰寫了一篇論文,題目為“Mocks, Stubs and Fakes: it's a continuum”,其部落格地址為:
http://www.clariusconsulting.net/blogs/kzu/archive/2007/12/21/47152.aspx
最終,Daniel Cazzulino沒有使用Fowler/Meszaros針對類比和代理所作出的區別。他呼籲,大多數開發人員當引用Fowler/Meszaros所指的“代理”時應該使用“類比”代之,並且強調大家應當尊重這些詞語的日常語言使用習慣。
由於本文後面的內容將介紹Moq的用法,所以,我們也根據Daniel Cazzulino的做法把類比和代理合并到一起使用。
三、下載和安裝Moq
Moq是作為Google代碼工程的形式維護的。你可以從網址http://code.google.com/p/moq/處下載Moq的二進位形式及相關API參考文檔。
在下載Moq的二進位形式Moq.2.5.3-bin.zip並解壓後,你將得到如所示的幾個檔案。
注意到,中包含了一個程式集Moq.dll。當在Visual Studio中測試你的項目前,你必須添加對於此程式集的引用。當然,你還需要添加對於Moq命名空間的具體引用,以便可以使用其中提供的測試類別。
另外請注意:解壓結果中還一併提供了一個協助檔案Moq.chm。這是Windows平台上流行的協助檔案格式。通過此檔案,你可以詳細研究這個類比對象架構的使用。
在接下來的文章中,我將詳細介紹
如何使用Moq建立類比對象並編寫一個簡單的執行個體。
原文地址:http://space.itpub.net/14518332/viewspace-431738