單元測試是代碼正確性驗證的最重要的工具,也是系統測試當中最重要的環節。也是惟一須要編寫代碼才能進行測試的一種測試方法。在標準的開發過程當中,單元測試的代碼與實際程序的代碼具備同等的重要性。每個單元測試,都是用來定向測試其所對應的一個單元的數據是否正確。html
單元測試是由程序員本身來完成,最終受益的也是程序員本身。能夠這麼說,程序員有責任編寫功能代碼,同時也就有責任爲本身的代碼編寫單元測試。執行單元測試,就是爲了證實這段代碼的行爲和咱們指望的一致。程序員
單元測試還具備一下幾個好處:數據庫
可以協助程序員儘快找到BUG的具體位置編程
可以讓程序員對本身的程序更有自信網絡
可以讓程序員在提交項目以前就將代碼變的更加健壯數據結構
可以協助程序員更好的進行開發框架
可以向其餘程序員展示你的程序該如何調用編程語言
可以讓項目主管更瞭解系統的當前情況函數
在沒有單元測試的時代,咱們大多數的錯誤都是經過操做頁面的時候發現的。當咱們發現一個錯誤的時候,會根據異常拋出的地點來肯定是哪段代碼出現了問 題。可是大多數時候,咱們不會全部方法中都使用Try塊去處理異常(這一也是低效的)。所以一旦發現一個異常一般都是最頂層代碼拋出的,可是錯誤每每又是 在底層很深層次的某個對象中出現的。當咱們找到了這個最初拋出異常的方法的時候,咱們可能沒法得知這段代碼究竟是哪裏出了問題。只能逐行代碼的去查找,一 旦這個方法中使用的某個對象在外部有註冊事件或者有其餘的操做正在與當前方法同步進行,那麼就更難發現錯誤真正的緣由了。工具
有經驗的程序員也會知道,大多數的時候,咱們並非真正的在編寫新的代碼,而是在修改舊的代碼出現的錯誤。一般這個比例會大於2比8,這也是編寫代碼的時候的二八現象——編寫代碼的時間是二,而爲這段代碼找錯誤、修改錯誤所花費的時間倒是八。
在這種狀態之下,咱們在找錯誤的時候會直接編譯整個程序,而後經過界面逐步的操做到錯誤的地方而後再去查找代碼中是否有錯誤。這樣的找錯誤的方法效 率很是低。可是當咱們擁有單元測試的時候,咱們就不須要經過界面去一步一步的操做,而是直接運行這個方法的單元測試,將輸入的條件模擬成出現錯誤的時候輸 入的信息和調用的方法的形式,這樣就可能很快的還原出錯誤。這樣解決起來速度就提升了不少,每次找到錯誤都去修改單元測試,那麼下次就不會再出現相同的錯 誤了。
若是經過模擬,單元測試也沒有出現任何異常,這時也能夠判定,並不是該代碼出現的錯誤,而是其餘相關的代碼出現的錯誤。咱們只需再調試其餘幾個相關的代碼的單元測試便可找到真正的錯誤。
不少時候,當主管問咱們程序會不會再出問題的時候,咱們會很難回答。由於咱們無法估計到系統還可能出現什麼問題。可是若是這時咱們爲全部代碼都編寫 了單元測試,並且測試代碼的編寫是按照標準去寫的,這些測試又都可以成功的經過測試。那麼咱們就徹底有自信說出咱們的把握有多大。由於在測試代碼中,咱們 已經把全部可能的狀況都預料到了,程序代碼中也將這些可能預料到的問題都解決了。所以咱們會對本身的程序變得愈來愈自信。
大多數程序員在編寫代碼的時候,都會先考慮最理想化狀況下的程序該如何寫,寫完以後在理想狀態下編譯成功,而後輸入理想的數據發現沒有問題。他們就 會自我安慰的說「完成了」。而後可能爲了趕進度,就又開始做另外的程序了。時間久了這種理想化的程序就愈來愈多。一旦提交測試,就發現這裏有錯誤那裏有錯 誤,而後程序員們再拿出時間來這裏補個漏洞那裏補個漏洞。並且在補漏洞的過程當中,也可能繼續沿用這種理想化的思路,就致使了補了這裏又致使那裏出問題的情 況。
可是若是在初期,咱們就爲每段代碼編寫單元測試,並且根據一些既定的標準去寫,那麼單元測試就會提早告訴程序員哪些地方會出現錯誤。那麼他們可能在編寫過程當中就提早處理了那些非理想狀態下的問題。這樣咱們的代碼就會健壯不少。
「碼未動,測試現行。」這是極限編程中倡導的一種編程模式,爲何要這樣呢?由於咱們在編寫單元測試的過程當中,其實就是在設計咱們的代碼將要處理哪 些問題。單元測試寫的好,就表明你的代碼寫的好。並且你會根據單元測試的一些預先設想的狀況去編寫代碼,就不會盲目的添加一個屬性、添加一個方法了。
一般狀況下,單元測試代碼中寫的都是在各類狀況下如何調用那段待測試的代碼。所以這個單元測試同時也向其餘人員展現了咱們的代碼該如何調用?在什麼狀況下會拋出什麼異常?等等。這樣一個單元測試就變成了一個代碼性的幫助文檔了。
傳統的管理中,項目的進度、代碼的質量都只是經過口頭的形式傳遞到主管那裏的。所以有時候主管得到的反饋可能事實。可是若是經過一個完善的單元測試系統,那麼主管就能夠經過查看單元測試的運行結果和單元測試的代碼覆蓋率來肯定開發人員的工做是否真正完成。
Microsoft Visual Studio 2005中集成了一個專門用來進行測試的組件,該組件可以提供給咱們單元測試、壓力測試、代碼覆蓋率等等的測試相關的功能。咱們無須借用第三方的測試工具來進行這些測試。
該工具能夠對任何類、接口、結構等實體中的字段、屬性、構造函數、方法等進行單元測試。建立單元測試大體能夠分爲兩類:
總體測試,總體測試是在類名稱上右擊鼠標,在下拉菜單中點擊建立單元測試選項。這樣就能夠爲整個類建立單元測試了,這時他會爲整個類能夠被測試的內容所有添加測試方法。開發人員直接在這些自動生成的測試方法中添加單元測試代碼就能夠了。
單獨測試,若是隻想單獨對某個方法、屬性、字段進行測試,則能夠將鼠標焦點放在這個待測試的項目名稱之上,而後點擊鼠標右鍵,在右鍵菜單中選擇建立單元測試選項。這樣就能夠單獨爲某個方法建立單元測試了。
建立完單元測試以後,就能夠爲單元測試編寫測試代碼了。具體的測試代碼的編寫標準會在第三章中介紹。
單元測試代碼編寫完畢,就能夠經過運行單元測試來進行測試了。須要運行單元測試的時候,須要打開測試管理器窗口。該窗口能夠經過菜單中的「測試」- 「窗口」——「測試管理器」來打開。打開該窗口以後,就能夠在該窗口中看到咱們所創建的單元測試的列表。咱們能夠在列表中勾選某個單元測試前面的複選框。 而後右擊鼠標在右鍵菜單中點擊「調試選中的測試」或者「運行選中的測試」。
調試選中的測試的時候,咱們能夠在測試代碼中或者咱們本身的代碼中添加斷點並逐步運行以看其狀態。
運行選中的測試只會運行測試並不可以進行測試,這時代碼的運行是模擬真實軟件運行的時候的狀況執行的。咱們能夠根據咱們的實際狀況來選中執行哪一種測試。
運行了測試以後,咱們須要查看此次測試的結果。咱們能夠經過點擊菜單中的「測試」——「窗口」——「測試結果」來打開一個測試結果窗口。每次測試都會在測試結果中向咱們顯示一些記錄。咱們也能夠經過雙擊這個測試結果,來查看詳細的結果信息。
單元測試寫的是否合理或者是否達到了要求的一個惟一的標準就是整個測試的代碼覆蓋率。代碼覆蓋率其實就是測試代碼所運行到的實際程序路徑的覆蓋率。 在實際程序中可能會有不少的循環、判斷等分支路徑。一個好的單元測試應該可以將全部可能的路徑都將走到,這樣就能夠保證大多數狀況都測試過了。
VS2005中也提供了查看代碼覆蓋率的工具。咱們能夠經過點擊菜單中的「測試」——「窗口」——「代碼覆蓋率結果」來打開代碼覆蓋率查看的窗口。
若要進行代碼覆蓋率的檢查,咱們必須進行設置,由於系統默認狀況下是不進行代碼覆蓋率檢測的。若要打開某個測試的代碼覆蓋率測試,咱們必須點擊菜單 中的「測試」——「編輯測試運行配置」——「本地測試運行。。。。。。」來打開一個測試配置窗口。在該窗口左側的列表中選中「代碼覆蓋率」就會顯示代碼覆 蓋率的設置。在這個配置中會顯示當前解決方案中能夠用來檢測代碼覆蓋率的程序集,咱們將須要進行覆蓋率檢測的程序集選中而後點擊「應用」按鈕就能夠了。
設置完畢以後,咱們就能夠直接運行單元測試,測試經過後。咱們就能夠打開代碼覆蓋率結果窗口,在這裏咱們就可以看到這些測試覆蓋了多少代碼。當咱們 在這裏雙擊某個類的時候,就能夠看到VS已經將代碼背景改變了顏色。顯示爲深棕色的代碼就是沒有覆蓋到的代碼,咱們能夠經過在單元測試代碼中添加代碼來想 辦法覆蓋這些代碼。這樣一個單元測試的全過程就完成了。
雖然要進行單元測試的代碼會是各類各樣的,可是編寫單元測試代碼仍是有規律可循的。測試的對象通常狀況下分爲方法(包含構造函數)、屬性,所以咱們按照這兩個方向來肯定單元測試的標準。
因爲如今大多數開發人員尚未真正使用過.NET的單元測試工具,對於單元測試的瞭解程度也不高。所以咱們這裏也不便於制定很是多的標準。咱們當前主要針對兩大方面進行規範:
l 哪些代碼須要添加單元測試?
l 單元測試代碼的寫法?
當前項目正處在一個最後衝刺階段,主要的大部分編碼工做已經基本完成。所以要全面的添加單元測試,實際上是比較大的投入。因此單元測試不能一次性的所有加上,咱們只能經過一步一步的來進行測試。
第一步,應該對全部程序集中的公開類以及公開類裏面的公開方法添加單元測試。
第二步,對於構造函數和公共屬性進行單元測試。
第三步,添加全面單元測試。
在產品全面提交以前能夠先完成第一步的工做,二三步能夠待其餘全部功能完成以後再進行添加。因爲第二三步的添加工做其實於第一步相似,只是在量上的累加,所以咱們先着重討論第一步的狀況。
在做第一步單元測試添加的時候,也須要有選擇性的進行,咱們要抓住重點進行測試。首先應該針對屬於框架技術中的代碼添加單元測試。這裏就包含操做數 據庫的組件、操做外部WebService的組件、郵件接收發送組件、後臺服務與前提程序之間的消息傳遞的組件等等。經過爲這些主要的可複用代碼進行測 試,能夠大大增強底層操做的正確性和健壯性。
其次爲業務邏輯層對界面公開的方法添加單元測試。這樣可讓業務邏輯保持正確,而且可以將大部分的業務操做都概括到單元測試中,保證之後產品發佈以後,一旦出現問題能夠直接經過業務邏輯的單元測試來找到BUG。
剩下的代碼大部分屬於代碼生成器生成的,並且大多數的操做都是相似的,所以咱們能夠先針對某一個業務邏輯對象作詳細的單元測試。經過這樣的規定,單元測試添加的範圍就減小了不少。
在編寫單元測試代碼的時候須要認真的考慮如下幾個方面:
l 所測試的方法的代碼覆蓋率必須達到100%。
l 所測試的代碼內部的狀態,例如執行了某個方法以後,該方法所在的類中某個屬性或者返回值是否與預期相同。
l 被測試代碼所使用的外部設備的狀態,如數據庫是否可讀、網絡是否可用、打印機是否可用、WebService是否可用等等。
每一段單元測試代碼,必須考慮到以上的三個問題,而且對於這些問題都要有相應的測試。
在2.5小節中已經講了什麼是代碼覆蓋率和代碼覆蓋率查看的方法。在這裏咱們着重來說怎樣將代碼覆蓋率提高到100%。
通常狀況下,代碼覆蓋率低,說明測試代碼中沒有過多的考慮某些特殊狀況。特殊狀況包括:
l 邊界條件數據,好比值類型數據的最大值、最小值、DBNull,或者是方法中所使用的條件邊界,例如a>100那麼100就變成了這個數據的邊界。並且在測試的時候還必須把超出邊界的數據做爲測試條件進行測試。
l 空數據,通常空數據對應於引用類型的數據,也就是Null值。
l 格式不正確數據,對於引用類型的數據或者結構對象,類型雖然正確可是其內部的數據結構不正確的數據。例如一個數據庫實體對象,數據庫中要求其某個屬性必須爲非空,可是這時咱們能夠屬於一個空。這樣這個對象就屬於一個不正確數據庫。
這三種數據都是針對被測試方法中所使用的外部數據來講的。方法中使用的外部數據無非就是方法參數傳入的數據和方法所在的對象的屬性或者字段的數據。 所以在編寫測試代碼的時候就必須將這些使用到的數據設置爲上面這幾種狀況的數據來檢測方法執行的狀況。這才能保證方法編寫是正確的。
在編寫單元測試代碼的時候先了解到被測試方法可能會使用的外部數據,而後將這些外部數據一次設置爲上面規定的這幾種狀況,而後再執行方法。這樣就基本能夠達到外部數據全部狀況都可以正確測試到了。
經過這種方法編寫的單元測試代碼覆蓋率通常能夠超過80%。
在編寫單元測試的時候,不能單純的追求代碼覆蓋率。有時候代碼覆蓋率已經達到了100%,程序也能正常運行,可是可能會出現方法執行完畢以後某些數 據並不是預期的數值。這時就必須對執行的結果進行斷言。在.NET提供的單元測試模塊中,能夠在單元測試中直接使用一個類的一些靜態方法來判斷某個值是否達 到了預期的狀況。這個類是Assert。在這個類中公開了不少判斷等效性、判斷開關性、判斷非空性等一系列方法。這些方法可讓你提早作出預測,一旦程序 執行以後,若是這些斷言不能經過,就表明代碼有錯誤。
在使用斷言的時候,咱們要求要達到平均5行測試代碼就要有一個斷言。
經過添加斷言,咱們就能夠對程序執行過程當中數據的正確性作一個檢測,保證咱們的程序不出現寫錯數據的狀況或者出現錯誤狀態的狀況。
當代碼覆蓋率和預期值都達到了咱們的要求以後,整個程序其實就基本達到了質量標準。可是這樣還不全面,由於不少程序都要使用到外部的設備或者程序, 例如數據庫、打印機、網絡、串行口、並行口等等。當這些設備發生改變或者不可用的時候,程序就可能出現一些不可預知的錯誤。所以一個健壯的程序也必須考慮 到這些狀況,這時一般都是經過將這些設備肯定的設置爲這些不正常狀態來檢測程序可能會出現的問題。而後再在測試程序中將這些條件加上。
單元測試(模塊測試)是開發者編寫的一小段代碼,用於檢驗被測代碼的一個很小的、很明確的功能是否正確。一般而言,一個單元測試是用於判斷某個特定 條件(或者場景)下某個特定函數的行爲。例如,你可能把一個很大的值放入一個有序list 中去,而後確認該值出如今list 的尾部。或者,你可能會從字符串中刪除匹配某種模式的字符,而後確認字符串確實再也不包含這些字符了。
單元測試是由程序員本身來完成,最終受益的也是程序員本身。能夠這麼說,程序員有責任編寫功能代碼,同時也就有責任爲本身的代碼編寫單元測試。執行單元測試,就是爲了證實這段代碼的行爲和咱們指望的一致。
工廠在組裝一臺電視機以前,會對每一個元件都進行測試,這,就是單元測試。
其實咱們天天都在作單元測試。你寫了一個函數,除了極簡單的外,老是要執行一下,看看功能是否正常,有時還要想辦法輸出些數據,如彈出信息窗口什麼 的,這,也是單元測試,老納把這種單元測試稱爲臨時單元測試。只進行了臨時單元測試的軟件,針對代碼的測試很不完整,代碼覆蓋率要超過70%都很困難,未 覆蓋的代碼可能遺留大量的細小的錯誤,這些錯誤還會互相影響,當BUG暴露出來的時候難於調試,大幅度提升後期測試和維護成本,也下降了開發商的競爭力。 能夠說,進行充分的單元測試,是提升軟件質量,下降開發成本的必由之路。
對於程序員來講,若是養成了對本身寫的代碼進行單元測試的習慣,不但能夠寫出高質量的代碼,並且還能提升編程水平。
要進行充分的單元測試,應專門編寫測試代碼,並與產品代碼隔離。老納認爲,比較簡單的辦法是爲產品工程創建對應的測試工程,爲每一個類創建對應的測試類,爲每一個函數(很簡單的除外)創建測試函數。首先就幾個概念談談老納的見解。
通常認爲,在結構化程序時代,單元測試所說的單元是指函數,在當今的面向對象時代,單元測試所說的單元是指類。以老納的實踐來看,以類做爲測試單位, 複雜度高,可操做性較差,所以仍然主張以函數做爲單元測試的測試單位,但能夠用一個測試類來組織某個類的全部測試函數。單元測試不該過度強調面向對象,因 爲局部代碼依然是結構化的。單元測試的工做量較大,簡單實用高效纔是硬道理。
有一種見解是,只測試類的接口(公有函數),不測試其餘函數,從面向對象角度來看,確實有其道理,可是,測試的目的是找錯並最終排錯,所以,只要是包 含錯誤的可能性較大的函數都要測試,跟函數是否私有沒有關係。對於C++來講,能夠用一種簡單的方法區隔需測試的函數:簡單的函數如數據讀寫函數的實如今 頭文件中編寫(inline函數),全部在源文件編寫實現的函數都要進行測試(構造函數和析構函數除外)。
爲何要使用單元測試
咱們編寫代碼時,必定會反覆調試保證它可以編譯經過。若是是編譯沒有經過的代碼,沒有任何人會願意交付給本身的老闆。但代碼經過編譯,只是說明了它的語法正確;咱們卻沒法保證它的語義也必定正確,沒有任何人能夠輕易承諾這段代碼的行爲必定是正確的。
幸運,單元測試會爲咱們的承諾作保證。編寫單元測試就是用來驗證這段代碼的行爲是否與咱們指望的一致。有了單元測試,咱們能夠自信的交付本身的代碼,而沒有任何的後顧之憂。
何時測試?單元測試越早越好,早到什麼程度?XP開發理論講究TDD,即測試驅動開發,先編寫測試代碼,再進行開發。在實際的工做中,能夠沒必要過 分強調先什麼後什麼,重要的是高效和感受溫馨。從老納的經驗來看,先編寫產品函數的框架,而後編寫測試函數,針對產品函數的功能編寫測試用例,而後編寫產 品函數的代碼,每寫一個功能點都運行測試,隨時補充測試用例。所謂先編寫產品函數的框架,是指先編寫函數空的實現,有返回值的隨便返回一個值,編譯經過後 再編寫測試代碼,這時,函數名、參數表、返回類型都應該肯定下來了,所編寫的測試代碼之後需修改的可能性比較小。
由誰測試?單元測試與其餘測試不一樣,單元測試可看做是編碼工做的一部分,應該由程序員完成,也就是說,通過了單元測試的代碼纔是已完成的代碼,提交產品代碼時也要同時提交測試代碼。測試部門能夠做必定程度的審覈。
關於樁代碼,老納認爲,單元測試應避免編寫樁代碼。樁代碼就是用來代替某些代碼的代碼,例如,產品函數或測試函數調用了一個未編寫的函數,能夠編寫樁 函數來代替該被調用的函數,樁代碼也用於實現測試隔離。採用由底向上的方式進行開發,底層的代碼先開發並先測試,能夠避免編寫樁代碼,這樣作的好處有:減 少了工做量;測試上層函數時,也是對下層函數的間接測試;當下層函數修改時,經過迴歸測試能夠確認修改是否致使上層函數產生錯誤。
在一種傳統的結構化編程語言中,好比C,要進行測試的單元通常是函數或子過程。在象C++這樣的面向對象的語言中, 要進行測試的基本單元是類。對Ada語言來講,開發人員能夠選擇是在獨立的過程和函數,仍是在Ada包的級別上進行單元測試。單元測試的原則一樣被擴展到 第四代語言(4GL)的開發中,在這裏基本單元被典型地劃分爲一個菜單或顯示界面。
單元測試不只僅是做爲無錯編碼一種輔助手段在一次性的開發過程當中使用,單元測試必須是可重複的,不管是在軟件修改,或是移植到新的運行環境的過程當中。所以,全部的測試都必須在整個軟件系統的生命週期中進行維護。
常常與單元測試聯繫起來的另一些開發活動包括代碼走讀(Code review),靜態分析(Static analysis)和動態分析(Dynamic analysis)。靜態分析就是對軟件的源代碼進行研讀,查找錯誤或收集一些度量數據,並不須要對代碼進行編譯和執行。動態分析就是經過觀察軟件運行時的動做,來提供執行跟蹤,時間分析,以及測試覆蓋度方面的信息。
一些流行的誤解
在明確了什麼是單元測試之後,咱們能夠進行"反調論證"了。在下面的章節裏,咱們列出了一些反對單元測試的廣泛的論點。而後用充分的理由來證實這些論點是不足取的。
它浪費了太多的時間
一旦編碼完成,開發人員老是會迫切但願進行軟件的集成工做,這樣他們就可以看到實際的系統開始啓動工做了。 這在外表上看來是一項明顯的進步,而象單元測試這樣的活動也許會被看做是通往這個階段點的道路上的障礙, 推遲了對整個系統進行聯調這種真正有意思的工做啓動的時間。
在這種開發步驟中,真實意義上的進步被外表上的進步取代了。系統可以正常工做的可能性是很小的,更多的狀況是充滿了各式各樣的Bug。在實踐中,這樣 一種開發步驟經常會致使這樣的結果:軟件甚至沒法運行。更進一步的結果是大量的時間將被花費在跟蹤那些包含在獨立單元裏的簡單的Bug上面,在個別狀況 下,這些Bug也許是瑣碎和微不足道的,可是總的來講,他們會致使在軟件集成爲一個系統時增長額外的工期, 並且當這個系統投入使用時也沒法確保它可以可靠運行。
在實踐工做中,進行了完整計劃的單元測試和編寫實際的代碼所花費的精力大體上是相同的。一旦完成了這些單元測試工做,不少Bug將被糾正,在確信他們 手頭擁有穩定可靠的部件的狀況下,開發人員可以進行更高效的系統集成工做。這纔是真實意義上的進步,因此說完整計劃下的單元測試是對時間的更高效的利用。 而調試人員的不受控和散漫的工做方式只會花費更多的時間而取得不多的好處。
使用AdaTEST和Cantata這樣的支持工具可使單元測試更加簡單和有效。但這不是必須的,單元測試即便是在沒有工具支持的狀況下也是一項很是有意義的活動。
它僅僅是證實這些代碼作了什麼
這是那些沒有首先爲每一個單元編寫一個詳細的規格說明而直接跳到編碼階段的開發人員提出的一條廣泛的抱怨, 當編碼完成之後而且面臨代碼測試任務的時候,他們就閱讀這些代碼並找出它實際上作了什麼,把他們的測試工做基於已經寫好的代碼的基礎上。固然,他們沒法證 明任何事情。全部的這些測試工做可以代表的事情就是編譯器工做正常。是的,他們也許可以抓住(但願可以)罕見的編譯器Bug,可是他們可以作的僅僅是這 些。
若是他們首先寫好一個詳細的規格說明,測試可以以規格說明爲基礎。代碼就可以針對它的規格說明,而不是針對自身進行測試。這樣的測試仍然可以抓住編譯 器的Bug,同時也能找到更多的編碼錯誤,甚至是一些規格說明中的錯誤。好的規格說明可使測試的質量更高,因此最後的結論是高質量的測試須要高質量的規 格說明。
在實踐中會出現這樣的狀況: 一個開發人員要面對測試一個單元時只給出單元的代碼而沒有規格說明這樣吃力不討好的任務。你怎樣作纔會有更多的收穫,而不只僅是發現編譯器的Bug?第一 步是理解這個單元本來要作什麼, --- 不是它實際上作了什麼。 比較有效的方法是倒推出一個概要的規格說明。這個過程的主要輸入條件是要閱讀那些程序代碼和註釋, 主要針對這個單元, 及調用它和被它調用的相關代碼。畫出流程圖是很是有幫助的,你能夠用手工或使用某種工具。 能夠組織對這個概要規格說明的走讀(Review),以確保對這個單元的說明沒有基本的錯誤, 有了這種最小程度的代碼深層說明,就能夠用它來設計單元測試了。
我是個很棒的程序員, 我是否是能夠不進行單元測試?
在每一個開發組織中都至少有一個這樣的開發人員,他很是擅長於編程,他們開發的軟件老是在第一時間就能夠正常運行,所以不須要進行測試。你是否常常聽到這樣的藉口?
在真實世界裏,每一個人都會犯錯誤。即便某個開發人員能夠抱着這種態度在不多的一些簡單的程序中應付過去。 但真正的軟件系統是很是複雜的。真正的軟件系統不能夠寄但願於沒有進行普遍的測試和Bug修改過程就能夠正常工做。
編碼不是一個能夠一次性經過的過程。在真實世界中,軟件產品必須進行維護以對操做需求的改變做出反應, 而且要對最初的開發工做遺留下來的Bug進行修改。你但願依靠那些原始做者進行修改嗎? 這些製造出這些未經測試的原始代碼的資深專家們還會繼續在其餘地方製造這樣的代碼。在開發人員作出修改後進行可重複的單元測試能夠避免產生那些使人不快的 負做用。
無論怎樣, 集成測試將會抓住全部的Bug
咱們已經在前面的討論中從一個側面對這個問題進行了部分的闡述。這個論點不成立的緣由在於規模越大的代碼集成意味着複雜性就越高。若是軟件的單元沒有事先進行測試,開發人員極可能會花費大量的時間僅僅是爲了使軟件可以運行,而任何實際的測試方案都沒法執行。
一旦軟件能夠運行了,開發人員又要面對這樣的問題: 在考慮軟件全局複雜性的前提下對每一個單元進行全面的測試。 這是一件很是困難的事情,甚至在創造一種單元調用的測試條件的時候,要全面的考慮單元的被調用時的各類入口參數。在軟件集成階段,對單元功能全面測試的復 雜程度遠遠的超過獨立進行的單元測試過程。
最後的結果是測試將沒法達到它所應該有的全面性。一些缺陷將被遺漏,而且不少Bug將被忽略過去。
讓咱們類比一下,假設咱們要清洗一臺已經徹底裝配好的食物加工機器!不管你噴了多少水和清潔劑,一些食物的小碎片仍是會粘在機器的死角位置,只有任其 腐爛並等待之後再想辦法。但咱們換個角度想一想,若是這臺機器是拆開的, 這些死角也許就不存在或者更容易接觸到了,而且每一部分均可以絕不費力的進行清洗。
它的成本效率不高
一個特定的開發組織或軟件應用系統的測試水平取決於對那些未發現的Bug的潛在後果的重視程度。這種後果的嚴重程度能夠從一個Bug引發的小小的不便 到發生屢次的死機的狀況。這種後果可能經常會被軟件的開發人員所忽視(可是用戶可不會這樣),這種狀況會長期的損害這些向用戶提交帶有Bug的軟件的開發 組織的信譽,而且會致使對將來的市場產生負面的影響。相反地,一個可靠的軟件系統的良好的聲譽將有助於一個開發組織獲取將來的市場。
不少研究成果代表,不管何時做出修改都要進行完整的迴歸測試,在生命週期中儘早地對軟件產品進行測試將使效率和質量獲得最好的保證。Bug發現的 越晚,修改它所需的費用就越高,所以從經濟角度來看, 應該儘量早的查找和修改Bug。在修改費用變的太高以前,單元測試是一個在早期抓住Bug的機會。
相比後階段的測試,單元測試的建立更簡單,維護更容易,而且能夠更方便的進行重複。從全程的費用來考慮, 相比起那些複雜且曠日持久的集成測試,或是不穩定的軟件系統來講,單元測試所需的費用是很低的。
結論
經驗代表一個盡責的單元測試方法將會在軟件開發的某個階段發現不少的Bug,而且修改它們的成本也很低。在軟件開發的後期階段,Bug的發現並修改將 會變得更加困難,並要消耗大量的時間和開發費用。不管何時做出修改都要進行完整的迴歸測試,在生命週期中儘早地對軟件產品進行測試將使效率和質量獲得 最好的保證。 在提供了通過測試的單元的狀況下,系統集成過程將會大大地簡化。開發人員能夠將精力集中在單元之間的交互做用和全局的功能實現上,而不是陷入充滿不少 Bug的單元之中不能自拔。
使測試工做的效力發揮到最大化的關鍵在於選擇正確的測試策略,這其中包含了徹底的單元測試的概念,以及對測試過程的良好的管理,還有適當地使用象 AdaTEST和Cantata這樣的工具來支持測試過程。這些活動能夠產生這樣的結果:在花費更低的開發費用的狀況下獲得更穩定的軟件。更進一步的好處 是簡化了維護過程並下降了生命週期的費用。有效的單元測試是推行全局質量文化的一部分,而這種質量文化將會爲軟件開發者帶來無限的商機。