1、我們應該怎么做
編寫代碼之前,先編寫單元測試,即測試先行。也是所謂的測試驅動開發(fā)(TDD)
單元測試是代碼的一部分,所有的代碼必須有單元測試,并且測試通過。
在修改代碼之前,先修改單元測試,并且測試通過。
當我們在對代碼進行重構和進行設計優(yōu)化時,如果我們對所有的類都編寫了測試,那么我們重構代碼的時候很輕松的進行測試我們的修改是否正確。
當我們接到一個bug報告后,我們總是先修改測試代碼,然后修改實現(xiàn)代碼,使之測試成功。
2、為什么要編寫單元測試
編寫單元測試并不會增加了工作負擔延緩項目進度
(1)、以一個web應用開發(fā)為例:業(yè)務代碼編寫完成->打包->發(fā)布到服務器->進行功能測試->發(fā)現(xiàn)問題->修改代碼->再打包……如此循環(huán)。
任何一個web程序員對于這種開發(fā)情景都不會感到陌生。往往不斷的打包,發(fā)布,功能測試的時間是代碼編寫的10倍以上。
通過集成系統(tǒng)來發(fā)現(xiàn)程序的bug,我們往往很難一下子準確的定位bug產生的地方。如果第一次沒徹底修改這個bug或者修改這個bug已經(jīng)影響到其它的地方,這樣部署上去肯定又有bug。又的業(yè)務代碼編寫完成->打包->發(fā)布到服務器->進行功能測試。
如果為每一個類都編寫單元測試并讓每一個方法測試通過,又會是怎么樣的開發(fā)情景呢?
編寫測試代碼->編寫業(yè)務代碼->運行測試方法->修改代碼讓測試通過->所有的類都通過測試->打包->發(fā)布到服務器->進行功能測試->發(fā)現(xiàn)bug->修改測試代碼->修改業(yè)務代碼->測試通過->再打包…如此循環(huán)。
這樣降低了打包->發(fā)布到服務器->進行功能測試的次數(shù)。
(2) 另外,如果沒有單元測試,會經(jīng)常出現(xiàn)一些低級的錯誤,如拼寫錯誤,空指針異常等。因為一個小小的拼寫錯誤而需要重新打包,發(fā)布一次。如果有單元測試,可以避免這些低級的錯誤。
(3)在離bug產生越近,修正bug越容易;在bug產生越遠,修正bug的代價越昂貴。假設我們去集成一個星期(甚至更長時間)前編寫的代碼,當發(fā)現(xiàn)問題時,我們已經(jīng)忘掉了很多重要的實現(xiàn)細節(jié),所以修改變得困難重重。
3、編寫單元測試的基本原則
(1)學會使用斷言:斷言是讓我們?yōu)榉椒ㄔO置一個期望值。當方法執(zhí)行結果與期望值不一致時,測試組件會報告測試不通過。
(2)大化測試覆蓋率:我們除了測試一個正確的路徑外,我們還需要測試方法的每一個分支邏輯。需要編寫盡可能多的測試程序邏輯的測試。寫一個充分的測試。
(3)不要依賴于測試方法的執(zhí)行順序:使用Junit來進行單元測試,它不能保證測試方法按照我們的意圖的順序來執(zhí)行。當一個測試類有多個測試方法時,我們不能讓一個測試方法必須在某一個測試之后執(zhí)行才能成功。Junit不能為我們做這樣的保證,我們不能依賴于測試方法的執(zhí)行順序。
(4)針對接口測試:我們有“針對接口編程”的oo設計原則。同樣對于測試,我們也需要針對接口測試。也是說在編寫單元測試時,測試對象總是使用接口,而不是使用具體類。
4、編寫單元測試的作用
單元測試能夠提高程序員對程序的信心,保證程序的質量,加快軟件開發(fā)速度,使程序易于維護。
5、編寫測試用例
public int divide(int a, int b) throws Exception{
if(0 == b){
throw new Exception("除數(shù)不能為0");
}
return a / b;
}