第189期 / July 5, 2013

研發新視界

分享到臉書!分享到維特!分享到噗浪!分享到Google+!分享到微博!轉寄友人友善列印

以Visual Studio 2012進行單元測試之使用心得

作者/簡宗宇

[發表日期:2013/7/5]

簡介

在撰寫程式的過程中,必然是要驗證看看該程式執行完畢時得到的結果是否達到自己預期。試著想像一下,每一次寫完程式碼後,我們都會如何驗證程式的結果呢?大概就是按下F5執行看看,然後看輸出結果符不符合自己的預期,接著再換些不同輸入,最後再看看結果,可是當發現執行結果不如自己預期結果的話,就只能一直修正bug,每當修正程式之後必須將程式再重新執行一次,以此不斷的循環下去,上述的動作便是缺乏測試的程式,將產生嚴重的後果,舉例來說,當程式設計師為了修改bug而在沒有測試的保護傘下又恐怕會引發更多的bug,如此循環下去的結果最終將導致整個專案的毀壞;為避免這種不良的循環產生,所以必須要有不需要修改內部的專案程式來保護程式碼,而測試專案中單元測試可以協助我們自動化驗證,以及提升開發品質,省時又省力。

在程式設計的領域中有許多種測試,單元測試只是測試中的一種,所以單元測試並不保證程式是完美的,但單元測試在所有測試當中是非常重要且基本的一種。在眾多的測試工具中,微軟的開發工具Visual Studio 2012提供了單元測試功能的專案,程式開發人員可以利用這個功能進行測試,也可以針對不同方法連進行驗證。接下來本文將會介紹如何使用Visual Studio 2012單元測試的專案。

何謂單元測試?

單元測試 (Unit Test) 就是一種由程式設計師自行測試功能的工作,它是一種白箱測試,也是在設計的過程中最基本且最為細節的測試,簡單來說就是希望在每一個測試的方法當中,皆有相當簡單且明確的意義,為了要證明某一項功能在某一個case下,程式是如預期一般運作,主要由程式開發人員負責測試程式碼每一段邏輯是否合乎預期,由於目標是要徹底測試,想當然這些測試工作的花費人力差不多等同於撰寫程式的人力,對於有時程、人力限制的軟體專案,單元測試並不是很容易推行的,常常有人會想問:「那推行單元測試有什麼好處?」,倘若系統程式碼有著非常完整的單元測試個案,那之後進行後續的整合是不是問題會比較少?若需求變動導致程式碼修改,透過這些單元測試個案進行?歸測試,能協助我們找出一些相關影響程式碼部份?不過要推行單元測試的一個大前提,那就是必須簡化單元測試開發流程,降低人力花費,盡可能自動化。

一、定義

單元測試必須與外部環境、類別、資源和服務獨立,且在程式當中是最小的測試單位,不具備邏輯且不能與其他程式有直接的相依性,這樣才是最單純的測試。在目標物件中,本身邏輯取得的結果是否符合設計者預期之結果是單元測試的最終目標,當然單元測試需要運作地非常快速,倘若單元測試還需要資料庫的資源,那麼代表執行單元測試,還需要設定好資料庫連線或外部服務設定,並且執行當中肯定會要花些許時間。上述其實就是隸屬於整合測試,而非單元測試。

二、方法

進行單元測試有以下簡單的三個大步驟,首先第一步驟是先確認需要被測試的目標程式,接著第二步驟是在該目標程式的方案內建立單元測試專案,在Visual Studio 2012環境下所建立的單元測試專案會自動加入Visual Studio Unit Testing Framework,也就是會自動加入Microsoft.VisualStudio.QualityTools.Unit-TestFramework組件,在每個測試類別都會有TestClass的屬性,且於每個測試方法都會有TestMethod的屬性,單元測試必須在測試方法中呼叫以及初始化測試目標,並且撰寫測試目標程式的方法,最後第三步驟,便是驗證預期結果與所得到的實際結果是否符合。根據上述三個步驟,以下我們將介紹如何實作以及畫面說明,在Visual Studio 2012預先建立準備要進行測試的專案及目標程式,該目標程式內容為參數A加上參數B等於結果參數C,如圖一。於此方案內新增一個新的單元測式專案,如圖二。


《圖一》目標程式



《圖二》新增單元測試專案


根據上述三個步驟中的第二步驟中,在完成建立專案之後,將要測試的程式加入測試專案參考中,此時我們應該將測試目標初始化,並且撰寫測試目標程式的方法。在單元測試專案中撰寫程式時就應該要先明白該目標程式是做哪些事情,例如在圖一中,雖然目標程式主要目的是希望參數A加上參數B等於結果整數C,但在傳入參數時,如果參數能夠成功轉型為整數就會進行加法的動作,反之失敗就會顯示錯誤訊息,所以在進行單元測試時,依照定義中獨立服務的特性,必須拆成兩條路線來進行測試的Method,其中一種測試的路線Method為轉型成功,並且輸出加法結果,而另一種測試的路線Method為轉型失敗,並且輸出錯誤訊息,以下我們先以成功的Method撰寫程式,如圖三為傳入整數1與整數2的參數,成功轉型為整數的程式碼,該目標程式的預期結果為整數3。


《圖三》單元測試程式碼-轉型成功


在測試專案中,當然也與一般程式一樣可以使用偵錯的方式來執行程式,但是在單元測試中所建立的專案,最方便的方法是利用內建的測試總管來進行執行,所以在建立測式專案後,應該就能在畫面中尋找到測試總管, 如果在視窗中尋找不到測試總管,可以在Visual Studio 2012功能表上的〔測試〕選擇〔視窗〕,然後選取 〔測試總管〕便會顯示出來;測試總管的優點是在進行執行、寫入、重新執行測試時,就會顯示預設檢視結果,如:「通過的測試」、「尚未執行的測試」和「失敗的測試」,簡言之就是在撰寫測試程式的同時,於專案中的TestClass下每寫入或是修改一個TestMethod都會在測試總管「自動」顯示尚未執行的測試。在測試總管中,不僅僅只有檢視功能,另外如圖四中數字1紅框部分,功能是可以選擇〔全部執行〕來執行所有測試,抑或選取 〔執行〕 選取自己想測試的TestMethod;若想要在程式建置後執行單元測試,不想每次寫完程式還要再選擇一次全部執行的話,便可選取圖四中數字2紅框部分,這樣便可在建置程式後自動全部執行;若想要依照分類群組測試,便可選取 〔群組依據 結果〕的按鈕,如果碰上需要大量測試時,亦可以利用搜尋方塊輸入關鍵字進行篩選, 在篩選條件中是可以選取一個或多個篩選條件,如圖四中數字3紅框部分。


《圖四》測試總管


利用上述的測試總管來執行圖三的程式,在測試總管中會顯示綠色打勾的圖示與測試成功的字眼以及執行此TestMethod的耗用時間,如圖五。


《圖五》測試成功


如果在測試總管中所預期結果不符,測試總管會說明其預期結果是什麼,舉例來說,將圖三中如果將預期結果改為2,重新建置後再執行一次測試,便會發現測試總管出現紅色叉叉與測試失敗的字眼,並且顯示訊息與預期結果不一致,如圖六。


《圖六》測試失敗


在測試專案中,單元測試必須將目標程式的路徑盡量全部涵蓋,為什麼要將路徑盡量全部涵蓋呢?因為這樣才可以確保每一段目標程式皆有經過測試。那又該如何才能確保程式有被測試程式涵蓋以及涵蓋的範圍呢?在Visual Studio 2012中,建有程式碼涵蓋範圍結果的工具,此工具能夠協助我們顯示出整體目標程式與測試程式的涵蓋率,也詳細地提供每個Method所涵蓋的比例,並且可以將其資料匯入或匯出,以及顯示程式涵蓋範圍的著色,讓測試人員更快辨識該程式區域是否被涵蓋,相當快速與方便,如圖七為圖三範例中目前的涵蓋範圍。


《圖七》程式碼涵蓋範圍結果


圖七中,程式未被涵蓋的部分是以紅色顯示,為了提升目標程式的涵蓋率,以下我們便以另一種測試的路線Method撰寫程式,因為目標程式有做到Exception,所以在測試程式中,我們將需要的參數分別傳入整數1與文字2的參數,故意讓測試程式能夠轉型失敗發生Exception,如圖八,並且顯示出錯誤訊息,最後檢視程式碼涵蓋範圍結果,確認目標程式Exception的功能有被測試程式涵蓋與達到預期中會發生Exception的結果,如圖九。


《圖八》單元測試程式碼-轉型失敗



《圖九》結果


總結

Visual Studio 2012中的單元測試與其他版本中最大改變就是可以支援各種不同的Unit Test Framework與內建Fake機制,以及測試總管完全與TestMethod為主,無須再切換介面,使程式開發人員可以利用Visual Studio 2012的單元測試檢查每段程式的預期結果,更快速、輕鬆找到問題點,針對與預期不符的程式碼進行修改然後再次進行測試,在此保護傘下,單元測試已不只是測試,雖然單元測試並不會使整合的問題變比較少,但它可以釐清哪些程式是對的,哪些是錯的,並將問題範圍縮小,也提供程式開發人員一個安全的觀點,同時幫助別人更快速的維護與理解程式,進而提升開發的彈性與設計,可以使專案團隊隨時隨地的重整以便讓程式變的更乾淨,同時也可以允許客戶隨時變更他們的需求,而不至於因為要新增某項功能或修而導致程式的不穩甚至破壞,因此可以提供客戶更好的服務及信賴度。

參考資料

1.使用單元測試驗證程式碼
2.單元測試基本概念
3.使用測試總管執行單元測試