VSTS 把單元測試變簡單了!

在《軟體工程與 Microsoft Visual Studio Team System》的第三章,裡面有提到一個與單元測試有關的真實案例,就從這個例子說起吧。我把這段故事貼上來:

「這個故事發生在2003 年,當微軟嘗試定義Visual Studio Team System 的需求時,對某一家銀行所做的訪談。在某個早晨舉辦的開放式焦點團體會議中,微軟團隊詢問他們開發軟體的一些實務作法,其中特別問到了有沒有實施單元測試。他們說單元測試對這家銀行的所有開發人員來說根本就是家常便飯,而且每次簽入(check-in)程式碼之前,都一定會先進行單元測試。

到了下午,微軟有一位負責軟體易用性的工程師就實地觀察了他們其中一位開發人員的工作情形(這也是它稱為情境訪談的原因)。這名開發人員寫了一些程式,這當中也執行了幾次簽入程式碼的動作。幾個小時之後,易用性工程師問道:「我看你做了好幾次簽入動作,可是你有做單元測試嗎?」「當然有啊!」他立刻回答:「我在每次簽入之前都有按F5 ── 這個動作就是單元測試啦。」(如果你沒用過 Visual Studio 的話,F5 就是編譯的快速鍵,跟測試一點關係也沒有。)之前他們自己陳述的單元測試實務根本就從沒發生過。在設計 VSTS 的時候,我們把這種誤解的現象視為一個機會,我們要把單元測試功能做到像這家銀行的開發人員所認為的那樣簡單、好用(見第 6 章「開發」)。」

沒人在乎單元測試?

也許您已經非常清楚單元測試的概念,甚至可能已經實戰經驗豐富了。然而,我卻碰過許多次類似的情形,誤把除錯當作單元測試;在接觸過的幾個專案的計畫書中,都有看到「單元測試」項目,裡面寫得很像那麼回事,可是一見面詢問之下,馬上就露餡兒(喔,原來他指的是單步除錯 o_O)。

難道就像〈沒人在乎軟體工程〉一樣,也沒有人在乎單元測試嗎?如果單元測試真的這麼好,為什麼大家口中經常提到的單元測試,卻僅只停留「口頭練習」階段,而沒有實際用在專案開發呢?

不過,這只是個人憑感覺的臆測,並沒有統計數據顯示軟體業有多少人瞭解或真正實行單元測試。搞不好我碰到的例子正好就是那少數中的少數罷了。

程式設計師為什麼不做單元測試,這個在 Test-Driven Development 和 Extreme Programming 相關的書籍、文章裡面都討論很多了,這裡就不細談,只分享一點自己使用 VSTS 撰寫單元測試的經驗。

先寫程式?先寫測試?

許多測試驅動開發和 XP 的擁護者都提倡先寫測試,再寫程式。由於先寫測試程式的緣故,這些測試當然不會通過,於是你就會撰寫實際的程式碼讓測試通過。等測試通過了,你又再寫更多測試,然後再寫更多程式......如此反覆循環,你的應用程式就逐漸完成了。可是,究竟有多少人能接受先寫測試的做法呢?或許先寫測試才是讓程式設計師不想寫單元測試的原因?

其實不用這麼煩惱,如果覺得心中已經浮現一些軟體設計的 idea 或架構,先寫點程式又有何妨?寫了一點程式之後,總會碰到一些特別重要的地方(例如交易處理或者複雜的演算法),需要更強大的防護網來確保程式能夠正確執行,這時候再加一點單元測試來確保某個底層或核心的處理函式正確無誤。這樣不也挺好?

我最近便是用先寫一點程式,再寫一點測試的反覆循環方式,逐漸完成一個 .NET 類別庫的設計。整個設計和程式撰寫的過程可以說相當愉快。當然啦,這有賴於 Visual Studio Team System 提供方便的單元測試功能。

大部分時候,我會先在紙上畫很粗略的類別圖(有時甚至連圖都稱不上,只是 idea 的呈現),等到覺得差不多該付諸實現時,就開始撰寫程式。我會一直寫,直到完成比較重要的 methods,再用 VSTS 幫我產生單元測試的程式碼。只要在想要測試的 method 上方點滑鼠右鍵,再點「Create Unit Tests」就行了。如下圖:

如果是第一次產生單元測試的程式碼,VSTS 會先幫你建立一個單元測試專案,所有單元測試的程式碼就放在這個測試專案裡(當然你也可以建立多個測試專案)。上圖的動作會令 VSTS 幫我產生 BrailleConverter.ToBrailleWord 方法的測試程式碼,你會得到像下面這樣的測試程式碼:


///
///A test for ToBrailleWord (string)
///

[TestMethod()] public void ToBrailleWordTest()
{
BrailleConverter target = new BrailleConverter();
string text = null; // TODO: Initialize to an appropriate value
BrailleWord expected = null;
BrailleWord actual;

actual = target.ToBrailleWord(text);
Assert.AreEqual(expected, actual,
"Huanlin.Braille.BrailleConverter.ToBrailleWord did not return the expected value." + "");
Assert.Inconclusive("Verify the correctness of this test method.");
}

VSTS 產生的測試程式碼提供了一個很好的起點,只要稍加修改就行了。以下是實際修改後的測試程式碼:

///
///A test for ToBrailleWord (string)
///
[TestMethod()]
public void ToBrailleWordTest()
{
BrailleConverter target = new BrailleConverter(brTbl);
// 測試結合韻.
string text = "我";
BrailleWord expected = new BrailleWord(text, " ㄨㄛˇ", "2420");
BrailleWord actual = target.ToBrailleWord(text);
Assert.AreEqual(expected, actual, "BrailleConverter.ToBrailleChar 測試失敗: " + text);
// 測試單音字.
text = "智";
expected = new BrailleWord(text, "ㄓ  ˋ", "AC8234");
actual = target.ToBrailleWord(text);
Assert.AreEqual(expected, actual, "BrailleConverter.ToBrailleChar 測試失敗: " + text);
// 測試標點符號.
// ......略
}


要執行測試時,只要從 VSTS 主選單點選 Test > Start Selected Test Project with/without Debugger,或直接從工具列點選測試鈕就行了。測試的結果就像建置專案的結果一樣會顯示在 VSTS 下方的視窗裡。參考下圖:
只要是測試通過的項目,就會像圖中一樣顯示綠色打勾的圖示。測試失敗的項目會是紅色打叉的圖示,測試結果不確定的項目則是黃色的警告圖示。

每次只要應用程式的 code 有修改,我就會去執行一下單元測試--反正只是按個鈕嘛,一點也不費力。當我看到一整排綠色打勾的圖示,我知道這次動到的程式碼並沒有把原有的功能破壞掉,我可以很放心的繼續寫其他程式。如果有出現紅色圖示,我也能夠透過單步除錯單元測試程式碼來迅速找到問題的原因--這實在是很棒的 bug 防護網啊,不是嗎?

因此,不管你是習慣先寫測試,還是先寫程式,VSTS 都能讓你很方便的完成單元測試的撰寫與測試工作。VSTS 真的把單元測試變簡單了。

Post Comments

技術提供:Blogger.