同時,選擇合適粒度的測試也很重要。各類測試自己的優點,例如集成測試在功能保護上體現效果更快;而單元測試卻會驅動內部質量的提升。如果條件允許,選擇多 種粒度的測試結合,別忘了之前提到的測試金字塔。我們無法為整個系統一下子建立完善的測試,但為某一個區域,是有可能的。
為遺留系統寫功能測試
功能測試處于測試金字塔的上端,它的穩定性相對較低,維護成本也較高。因此寫功能測試一定要關注提升它的穩定性,并降低維護成本,遺留系統在這幾個方面遇到的挑戰可能會更大。
最近我對一個Web系統建立基于WebDriver的功能進行測試,其中面臨的一個很大問題就是HTML頁面缺乏語義、很多元素的定位都得依靠位置等極不可 靠方式,一旦頁某些布局發生變化,就會影響到測試,維護成本很高。但事情總有兩面性,正是這些測試,讓頁面的重構和優化得到了團隊的重視。
影響功能測試穩定性的另一個重要因素是測試數據。對于團隊控制范圍內的系統,我的建議是隨著測試的建立逐步創建一套可靠的、覆蓋各種典型場景的測試數據準備腳本。由此,我們每次都重新建立干凈的測試數據,讓測試更加穩定和可控。
但在遺留系統中,有時會碰上更嚴峻的問題,系統依賴于第三方或其他不在控制范圍內的測試系統。功能測試會影響到測試數據,因此我們的測試很有可能無法重復執 行。當然,建立一個測試替身系統是一種選擇方案,但有時并不容易,至少短期之內。面對這種情況,我們的解決方案是讓測試程序和測試數據解耦。想象一下,如 果同樣的測試由一個測試人員手工執行,每次執行時不需要選擇相同的數據,而只需選擇“符合同樣要求”的數據。
例如一個電商系統,它出售數量 有限的商品,售完即止。測試數據庫中有大量不同商品,但每種商品數量所剩無幾。如果我們的商品購買測試程序針對某個特定商品,那么在運行幾次之后,商品就 會賣完,測試就不再具備可執行性。但測試人員不會這么傻,他每次都可以選擇還有剩余的商品進行購買測試。既然如此,我們的測試程序也同樣可以做到:只要根 據商品頁面上的信息識別出哪些商品有剩余,隨機或者有策略地選擇其中某個商品進行購買即可。
這樣,我們就讓測試程序和具體的測試數據得到了解耦,緩解了測試的不可重復執行性,使其更加穩定,維護成本也得到降低。除了上述方法,還有其他方式可以避免測試程序和測試數據的耦合。
功能測試程序,是在用一種自動化的方式代替人的手工執行,但同時也一定程度上丟失了手工執行的靈活性。讓功能測試程序保持靈活應變是我們在編寫測試程序時應該考慮的一個重點。
為遺留系統寫單元測試
為遺留系統寫單元測試會面臨和寫功能測試不一樣的挑戰,在復雜度及對人的能力要求上也可能會更高一些。原因并不在于測試,而在于遺留系統自身。遺留系統內部 的強耦合(依賴)及每個單元的高復雜度使得測試難以開展。例如最近我接觸的幾個遺留系統,線程池邏輯和業務邏輯交織在一起,SQL拼裝邏輯、ORM邏輯和 業務邏輯也交織在一起,一個方法往往幾百上千行,而且有很深的調用鏈。
為這樣的系統編寫單元測試,我們普遍遇到了這樣幾個問題。
1. 私有方法如何測試:我經常被問到的一個問題是“這個私有方法怎么測”?對于私有方法的測試,可能的答案是——不要對私有方法進行測試,只要測試公有方法, 就能覆蓋到私有方法。這個答案可能正確,但在遺留系統中,往往是錯誤的。很多時候,我會反問“為什么要對私有方法進行測試?”
下面這個例子(如圖2所示),是一個有較復雜邏輯的線程。但主要的邏輯存在于組裝和發起HTTP請求和解析返回的XML上。
圖2 一個有較復雜邏輯的線程
當想對私有方法進行測試時,往往意味著類過于復雜、私有方法承載著太多的職責,通過公有方法覆蓋私有方法的測試成本過高,難度太大。因此,更好的解決辦法是 分離職責、分而治之、單獨測試。通過分離職責,單獨對各部分邏輯進行測試,測試就會簡單很多,如圖3所示;另一個例子如圖4所示。
原文轉自:http://www.uml.org.cn/Test/201305025.asp