
在一個項目當中,開發(fā)者常常要做大量的測試工作,如單元測試,集成測試,回歸測試,壓力測試 .etc。當然,依據(jù)項目情況大小和開發(fā)者人員水平不同,測試涵蓋的方面自然也是不一樣的。一些測試需要相應的硬件和人力資源,一些需要專門的測試小組,另一些需要提供細致處理和長時間不間斷運行的環(huán)境。
但是今天說的單元測試則不同,它是一種看起來十分廉價和基礎(chǔ)的技術(shù)。它由后臺程序開發(fā)人員創(chuàng)建運行,單機運行,刨除代碼量以外,對一個完整的項目開發(fā)成本而言,所需的人力物力都是相對較小的。而長久以來的事實也已經(jīng)證明,單元測試對于代碼規(guī)范性和高效性,以及項目Bug的捕獲和解決都有很大的幫助。大多數(shù)開發(fā)者其實了解這樣的事實,只是因為一些內(nèi)在和外在的因素(通常是不重視,時間緊和嫌麻煩),往往不愿意進行這些測試,或者只在項目快要結(jié)束時才想起來,只是已經(jīng)為時已晚。
所以諸如TDD(測試驅(qū)動開發(fā))的項目開發(fā)方式,都提倡一個核心道理:單元測試應該早做,多做,這樣既避免了過度設(shè)計,對有效編碼,項目依賴解耦也有好處。而且我們始終要明確,單元測試的第一受益者,永遠是程序員。接下來,就讓我們來看看單元測試的一些相關(guān)情況,之后再在.NET項目中實際運行單元測試吧。
單元測試總覽
讓我們根據(jù)3W+1H原則,先對單元測試有個系統(tǒng)性認識吧
一、 什么是單元測試
當我們在談論單元測試的時候,我們在談些什么?!迳洗簶?/p>
按照維基百科上的說法,單元測試(Unit Testing)又稱為模塊測試, 是針對程序模塊(軟件設(shè)計的最小單位)來進行正確性檢驗的測試工作。程序單元是應用的最小可測試部件。在面向?qū)ο缶幊讨?,最小單元就是方法,包括基類、抽象類、或者派生類(子類)中的方法。按照通俗的理解,一個單元測試判斷某個特定場條件下某個特定方法的行為,如斐波那契數(shù)列算法,冒泡排序算法。
單元測試將被測試應用程序細分為一個個足夠小的基本單元,各個單元間相互獨立,互不影響。開發(fā)者能通過單元測試,證明被測試函數(shù)的行為確實和開發(fā)者期望的一致。為了滿足這個最基本的愿望,書寫單元測試前,我們不用考慮太多關(guān)于性能上的事情,這是之后優(yōu)化重構(gòu)該做的事情。
二、 為什么使用單元測試
愛做單元測試的程序員,代碼都不會太差。——古龍
上文說到,常常由于項目工期緊張,抑或是程序員自身原因的問題,團隊往往在項目接近完成時才進行測試。這其實是非常不提倡的一種做法。就好像我們雇了一批人給我們造房子,從地基開始,造到十幾層了,才用懸垂線來測房子傾斜度一樣不靠譜(假如這個比喻靠譜的話)。到時候高層依賴底層,高層調(diào)試時發(fā)現(xiàn)bug,又得讓我們返回底層查找問題,即便修改之后仍然通過了,但是想必很多朋友也遇到過項目代碼覆蓋度比較高,一改基礎(chǔ)方法影響一大片的問題吧。
所以當我們從一開始就進行正確的單元測試時,這些問題都是可以解決的。以下羅列出了幾個簡單的作用,以供參考?
二.1 快速定位
單元測試最基本的一個功能,就是快速定位代碼中的錯誤。從項目一開始,開發(fā)者便對所有的單元模塊進行測試的話,除了能盡早發(fā)現(xiàn)問題,另一方面對我們項目的持續(xù)開發(fā)無疑也是提供了極大的保障。
二.2 文檔記錄
當我們設(shè)計出一個良好的單元測試環(huán)境,我們勢必會對所有的基本單元進行測試,這時候,單元測試相對于為我們編寫了一份api文檔,我們隨時可以查閱方法相關(guān)參數(shù)和返回值,以及運行情況。
二.3 適應變更
單元測試允許程序員在之后的開發(fā)工作中重構(gòu)代碼,并且確保單元依然工作正確。這個過程就是為所有函數(shù)和方法編寫單元測試。在連續(xù)的單元測試環(huán)境中,只要設(shè)計出了良好的驗證手段,單元測試可以延續(xù)用于準確反映當任何變更發(fā)生時可執(zhí)行程序和代碼的表現(xiàn),幫助開發(fā)者優(yōu)化代碼邏輯和代碼結(jié)構(gòu)。
二.4 規(guī)范設(shè)計
進行單元測試時,開發(fā)者其實站在了一個觀察調(diào)試的上帝角度。無論是開發(fā)先于測試,還是測試先于開發(fā),單元測試都可以幫助我們將模塊設(shè)計成易測試,易調(diào)試,易重構(gòu)。在這個過程中,開發(fā)者的編碼能力和對業(yè)務的理解能力也將得到鍛煉
三、 開始時間
早?!斞?/p>
單元測試這東西,就跟戒煙一樣。每個煙民都知道吸煙的壞處(bug),一開始吸煙的時候也會有人提醒你趕快戒煙吧,但是你往往并不在意,等到年限一長(項目開發(fā)迭代多次),因為吸煙身體出現(xiàn)的問題越來越嚴重,你可能在這之前做過幾次體檢(集成測試),但是依然于事無補了,等這時候再懷念當初戒煙,乃至不抽煙的好,也是為時已晚。所以單元測試,就該在項目一開始的時候進行測試,在你起了“編寫單元測試太麻煩了,還是算了”的念頭的時候就該開始。博主代碼水平有限,無止盡的debug和bug提交已經(jīng)耗費了我很大的精力,所以這才下定決心開始單元測試之旅。
確實不可否認,剛開始就編寫單元測試常常要多花費幾倍的代碼量,但是隨著項目進行,當你把基礎(chǔ)方法都測試過以后,高層功能需要的代碼量反而會大大減少。這時候單元測試也在往集成測試遷移,這是一個順其自然的過程,同時為集成測試的簡化也提供了極大的便利。
四、 有效進行
單元測試最終呈現(xiàn)出來的效果還是一個或多個測試方法而已,編寫這些測試方法時,應該注意以下原則
Arrange 用于初始化一些被測試方法需要的參數(shù)或依賴的對象。
Act方法 用于調(diào)用被測方法進行測試。
Assert 用于驗證測試方法是否按期望執(zhí)行或者結(jié)果是否符合期望值
在這之前,我們當然需要區(qū)分出應用程序的每個基本單元,這里有個討巧的方法,就是對項目依賴進行自底而上的遍歷即可,我們并不需要多在意單元測試和集成測試的依賴關(guān)系。
其實在傳統(tǒng)的DDD驅(qū)動開發(fā)中,我們已經(jīng)見識了很多IAPPService和IRepository,以及IDomainService的依賴關(guān)系了,對于多個基本單元測試組裝的集成測試,我們這里也統(tǒng)一當做同一種東西來對待了,畢竟我們關(guān)注的還是測試本身。所謂工欲善其事必先利其器,.NET 平臺上強大的工具也是必不可少的,下文中將用XUnit和NSubstitute來進行所有的測試用例展示。
end
結(jié)尾送大家一些福利,軟件測試大禮包,需要的老鄉(xiāng)可以在評論區(qū)評論,我會在評論區(qū)送出
推薦閱讀: