#FormatImgID_6#
|
3. 如何編寫單元測試
在XP下強調單元測試必須由類包的編寫者負責編寫,這個限定對于我們設定的測試目標是必須的。因為只有這樣,測試才能保證對象的運行時態行為符合需求,而僅通過類接口的測試,我們只能確保對象符合靜態約束,因此這就要求我們在測試的過程中,必須開放一定的內部數據結構,或者針對特定的運行行為建立適當的數據記錄,并把這些數據暴露給特定的測試單元。這也就是說我們在編寫單元測試時必須對相應的類包進行修改,這樣的修改也發生在我們以前使用的測試方法中,因此以前的測試標記及其他一些測試技巧仍然可以在Junit測試中改進使用。
由于單元測試的總體目標是負責我們的軟件在運行過程中的正確無誤,因此在我們對一個對象編寫單元測試的時候,我們不但需要保證類的靜態約束符合我們的設計意圖,而且需要保證對象在特定的條件下的運行狀態符合我們的預先設定。還是拿數據庫緩沖池的例子說明,一個緩沖池暴露給其他對象的是一組使用接口,其中包括對池的參數設定、池的初始化、池的銷毀、從這個池里獲得一個數據連接以及釋放連接到池中,對其他對象而言隨著各種條件的觸發而引起池的內部狀態的變化是不需要知道的,這一點也是符合封裝原理的。但是池對象的狀態變化,譬如:緩存的連接數在某些條件下會增長,一個連接在足夠長的運行后需要被徹底釋放從而使池的連接被更新等等,雖然外部對象不需要明確,但是卻是程序運行正確的保證,所以我們的單元測試必須保證這些內部邏輯被正確的運行。
編譯語言的測試和調試是很難對運行的邏輯過程進行跟蹤的,但是我們知道,無論邏輯怎么運行,如果狀態的轉換符合我們的行為設定,那驗證結果顯然是正確的,因此在對一個對象進行單元測試的時候,我們需要對多數的狀態轉換進行分析和對照,從而驗證對象的行為。狀態是通過一系列的狀態數據來描述的,因此編寫單元測試首先分析出狀態的變化過程(狀態轉換圖對這個過程的描述非常清晰),然后根據狀態的定義確定分析的狀態數據,最后是提供這些內部的狀態數據的訪問。在數據庫連接池的例子中,我們對池實現的對象DefaultConnectionProxy的狀態變換進行分析后,我們決定把表征狀態的OracleConnectionCacheImpl對象公開給測試類。參見示例一
示例一 /** * 這個類簡單的包裝了oracle對數據連接緩沖池的實現。 * */ public class DefaultConnectionProxy extends ConnectionProxy { private static final String name = "Default Connection Proxy"; private static final String description = "這個類簡單的包裝了oracle對數據連接緩沖池的實現。"; private static final String author = "Ion-Global.com"; private static final int major_version = 0; private static final int minor_version = 9; private static final boolean pooled = true; private ConnectionBroker connectionBroker = null; private Properties props; private Properties propDescriptions; private Object initLock = new Object(); // Test Code Begin... /* 為了能夠了解對象的狀態變化,因此需要把表征對象內部狀態變化的部分私有變量提供公共的訪問接口 (或者提供讓同一個類包的訪問接口),以便使測試單元可以有效地判斷對象的狀態轉變, 在本示例中對包裝的OracleConnectionCacheImpl對象提供訪問接口。 */ OracleConnectionCacheImpl getConnectionCache() { if (connectionBroker == null) { throw new IllegalStateException("You need start the server first."); } return connectionBroker.getConnectionCache(); } // Test Code End... 在公開內部狀態數據後,我們就可以編寫我們的測試單元了,單元測試的選擇方法和選擇尺度已經在本文前面章節進行了說明, 但是仍然需要注意的是,由于assert方法會拋出一個error,你應該在測試方法的最后集中用assert相關方法進行判斷, 這樣可以確保資源得到釋放。 對數據庫連接池的例子,我們可以建立測試類DefaultConnectionProxyTest,同時建立數個test case,如下 示例二 /** * 這個類對示例一中的類進行簡單的測試。 |