所有代碼都需要單元測試覆蓋嗎?
單元測試(unit testing)已經越來越得到廣大開發者的認可。作為低成本、速度快、穩定度高的自動化測試手段,單元測試可以在類和函數級別對代碼進行質量守護,有助于避免尷尬、耗時的錯誤。當然,相比功能測試(Functional testing)和端到端測試(end-to-end testing),單元測試能夠寄予的產品級別的信心要略低一些,因而各個粒度的測試應該是相輔相成的,互為補充。
常常聽到一些組織要求開發團隊提高單元測試覆蓋率,換來的卻是怨聲載道,或者是一堆應付差事的垃圾測試(沒有斷言的測試,都見過吧)。盡管,低測試覆蓋率意味著對質量的信心不足,但是,單元測試覆蓋率真的要達到100%才好嗎?
100%聽起來肯定比95%要好,但是區別在于那些額外測試的價值對你可能是微不足道的。這要看哪種代碼沒有被測試覆蓋,以及你的測試能否暴露程序的錯誤。100%的覆蓋率并不能夠確保沒有缺陷——它只能保證你所有的代碼都執行了,而不管程序的行為是否滿足要求。與其追求代碼覆蓋率,不如將重點關注在確保寫出有意義的測試。
測試越多,額外測試的價值越少。第一個測試最有可能是針對代碼最重要的區域,因此帶來高價值與高風險。當我們為幾乎所有事情編寫測試后,那些仍然沒有測試覆蓋的地方很可能是最不重要和最不可能破壞的。
編寫一些測試是不費腦筋的,但隨著我們接近完全的代碼覆蓋率,我們不那么確定了——我們差不多已經為一切都編寫了測試,而剩下的沒有測試的代碼是微不足道,幾乎不會破壞。這就是所謂的收益遞減。要想從單元測試中獲得更多的收益,需要重新將單元測試從質量工具定位成設計工具。TDD等方式可以幫助我們做到這一點。
換句話說,向代碼基增加100個精挑細選的自動化測試是明顯的改善,但當我們已有30000個測試時,這些額外的100個測試就無足輕重了。
比賽場上的贏家是那些將注意力集中在賽場上的選手,而不是緊盯著計分板的人。—巴菲特
總之,當你覺得生產環境中報來的bug很少了,或者你能夠自信地對代碼隨時進行修改,單元測試就已經足夠多了。
另一方面,也有些觀點認為,不但不值得追求高覆蓋率,甚至寫單元測試本身就是非常耗時和難以維護的重復工作。這種極端觀點我同樣不贊同。
代碼覆蓋率不能告訴我們代碼質量的高低,也不能用了評判開發人員的績效。但它能夠告訴我們哪些代碼還沒有被測試覆蓋,哪里有漏網之魚。至于這魚值不值得抓,還是取決于開發人員的經驗進行風險判斷。那么,接下來我們再來分析一下,到底哪些魚值得抓。
unit-test-quadrants
圖中,產品代碼可以分為四個類別,縱軸是從單元測試中得到的收益,橫軸是單元測試的成本,我們從投入產出的角度來分析,到底哪些代碼適合于進行單元測試:
瑣碎且無甚依賴的代碼。比如getter/setter, 比如簡單地調用系統時間,比如 toString()等等,基本是不需要測試的。雖然測起來容易,但我們有信心說它們出錯的概率也非常低,測這種代碼的確索然無味。
承上啟下的代碼。比如用MVC框架實現的代碼里,某些service層只是簡單地被Action層調用,然后轉發到下一層去。這種粘合代碼不具備太多被測試的價值,而且由于是銜接上下兩層的傳話筒,測起來卻需要對周圍各層進行mock或打樁。要想驗證其所做的那一點點工作,其實還挺麻煩的。當然,也有一些觀點比如”London School TDD”堅持認為,對于企業級應用,就要像制作香腸一樣,一層一層地對交互(interaction-based)進行測試,每測一層都需要mock的幫助。
具有算法和業務邏輯的代碼。比如排序或處理數據等代碼,這些是最值得進行單元測試的代碼了。雖然有一定的成本,但是由于算法邏輯的輸入輸出非常確定,結構復雜且具有業務價值,外部依賴較少,在這上面投入是一定可以得到豐厚回報的。這即是”Classic TDD”觀點,對狀態進行測試(state-based)。
過于復雜的代碼。充滿復雜邏輯、交織在一起、散發著各種壞味道的遺留代碼,就像一座未開發的金礦,你需要做很多清理工作,才能順利地進行開采,否則將寸步難行,不知從何下手,而且成本極高。這種代碼建議先進行粗粒度重構和接口測試(孰先孰后要根據實際情況),破除掉嚴重的依賴,找到所謂的接縫(Seam),將具有邏輯的部分與承上啟下的代碼分離開,然后立即將單元測試注入到接縫中,形成對有邏輯代碼的保護網,隨后繼續縮小重構的范圍,不斷地添加測試和重構,逐漸滲透形成一張網,將又臭又硬的代碼塊切碎。
除了3)以外的代碼怎么測?可以采用其他測試手段,比如功能性測試來進行粗粒度覆蓋,同樣能提升對產品的信心,并且成本更低,特別適合敏捷迭代式開發,能夠在有限的時間盒內達到預期的質量水平。
此外,持續地重構代碼,同時編寫更有效的單元測試,也是敏捷開發者應該具備的基本功,有助于提高投入產出比。
posted on 2014-04-02 10:56 順其自然EVO 閱讀(290) 評論(0) 編輯 收藏 所屬分類: 測試學習專欄