您的位置:軟件測(cè)試 > 開(kāi)源軟件測(cè)試 > 開(kāi)源單元測(cè)試工具 >
C#的單元測(cè)試方法
作者:網(wǎng)絡(luò)轉(zhuǎn)載 發(fā)布時(shí)間:[ 2013/2/6 14:24:51 ] 推薦標(biāo)簽:

1.       自信的編碼

有一次——或許是上個(gè)禮拜二——有兩個(gè)開(kāi)發(fā)者:Pat 和Dale。他們面臨著相同的后期限,而這也越來(lái)越近了。Pat 每天都在著急地編寫(xiě)代碼,寫(xiě)完一個(gè)類(lèi)又寫(xiě)一個(gè)類(lèi),寫(xiě)完一個(gè)函數(shù)又接著寫(xiě)另一個(gè)函數(shù),還經(jīng)常不得不停下來(lái)做一些調(diào)整,使得代碼能夠通過(guò)編譯。

Pat 一直保持著這種工作方式,直到后期限的前。而這時(shí)已經(jīng)是演示所有代碼的時(shí)候了。Pat 運(yùn)行了上層的程序,但是一點(diǎn)輸出也沒(méi)有,什么都沒(méi)有。這時(shí)只好用調(diào)試器來(lái)單步跟蹤了。“Hmm,決不可能是這樣的”,Pat 想,“此時(shí)這個(gè)變量不是0 啊”。于是,Pat 只能回過(guò)頭來(lái)看代碼,嘗試著跟蹤一下這個(gè)難以琢磨的程序的調(diào)用流程。

時(shí)間已經(jīng)越來(lái)越晚了,Pat 找到并且糾正了這個(gè)bug;但在這個(gè)過(guò)程中,Pat 又找到了其他好幾個(gè)bug;如此幾次過(guò)后,bug 還是存在。而程序輸出那邊,仍然沒(méi)有結(jié)果。這時(shí),Pat 已經(jīng)筋疲力盡了,完全搞不清楚為什么會(huì)這樣,認(rèn)為這種(沒(méi)有輸出的)行為是毫無(wú)道理的。

而于此同時(shí),Dale 并沒(méi)像Pat 那么快地寫(xiě)代碼。Dale 在寫(xiě)一個(gè)函數(shù)的時(shí)候,會(huì)附帶寫(xiě)一個(gè)簡(jiǎn)短的測(cè)試程序來(lái)測(cè)試這個(gè)函數(shù)。這里沒(méi)有什么特殊的地方,只是添加了一個(gè)簡(jiǎn)單的測(cè)試,來(lái)判斷函數(shù)的功能是否和程序員期望的一致。顯然,考慮如何寫(xiě),然后把測(cè)試寫(xiě)出來(lái),是需要占用一定時(shí)間的;但是Dale 在未對(duì)剛寫(xiě)的函數(shù)做出確認(rèn)之前,是不會(huì)接著寫(xiě)新代碼的。也是說(shuō),只有等到已知函數(shù)都得到確認(rèn)之后,Dale 才會(huì)繼續(xù)編寫(xiě)下一個(gè)函數(shù),然后調(diào)用前面的函數(shù)等等。

在整個(gè)過(guò)程中,Dale 幾乎不使用調(diào)試器;而且對(duì)Pat 的模樣也有些困惑不解:只見(jiàn)他頭埋在兩手之間,嘀咕著各種難聽(tīng)的話(huà)語(yǔ),咒罵著計(jì)算機(jī),充血的眼球同時(shí)盯著好幾個(gè)調(diào)試窗口。

后期限終于到了,Pat 未能完成任務(wù)。而Dale 的代碼被集成到整個(gè)系統(tǒng)中,并且能夠很好地運(yùn)行。之后,在Dale 的模塊中,出現(xiàn)了一個(gè)小問(wèn)題;但是Dale 很快發(fā)現(xiàn)了問(wèn)題所在,在幾分鐘之內(nèi)解決了問(wèn)題。

現(xiàn)在,是該總結(jié)一下上面這個(gè)小故事的時(shí)候了:Dale 和Pat 的年紀(jì)相當(dāng),編碼能力相當(dāng),智力也差不多。的區(qū)別是Dale 非常相信單元測(cè)試;對(duì)于每個(gè)新寫(xiě)的函數(shù),在其他代碼使用這個(gè)函數(shù)并對(duì)它形成依賴(lài)之前,都要先做單元測(cè)試。

而Pat 則沒(méi)有這么做,他總是“知道”代碼的行為應(yīng)該和所期望的完全一樣,并且等到所有代碼都差不多寫(xiě)完的時(shí)候,才想起來(lái)運(yùn)行一下代碼。然而到了這個(gè)時(shí)候,要想定位bug,或者,甚至是確定哪些代碼的行為是正確的,哪些代碼的行為是錯(cuò)誤的,都為時(shí)已晚了。

2.       什么是單元測(cè)試

單元測(cè)試是開(kāi)發(fā)者編寫(xiě)的一小段代碼,用于檢驗(yàn)被測(cè)代碼的一個(gè)很小的、很明確的功能是否正確。通常而言,一個(gè)單元測(cè)試是用于判斷某個(gè)特定條件(或者場(chǎng)景)下某個(gè)特定函數(shù)的行為。例如,你可能把一個(gè)很大的值放入一個(gè)有序list  中去,然后確認(rèn)該值出現(xiàn)在list  的尾部。或者,你可能會(huì)從字符串中刪除匹配某種模式的字符,然后確認(rèn)字符串確實(shí)不再包含這些字符了。

執(zhí)行單元測(cè)試,是為了證明某段代碼的行為確實(shí)和開(kāi)發(fā)者所期望的一致。

對(duì)于客戶(hù)或終使用者而言,這種測(cè)試必要嗎,它與驗(yàn)收測(cè)試有關(guān)嗎?這個(gè)問(wèn)題仍然很難回答。事實(shí)上,我們?cè)诖瞬⒉魂P(guān)心整個(gè)產(chǎn)品的確認(rèn)、驗(yàn)證和正確性等等;甚至此時(shí),我們都不去關(guān)心性能方面的問(wèn)題。我們所要做的一切是要證明代碼的行為和我們的期望一致。因此,我們所要測(cè)試的是規(guī)模很小的、非常獨(dú)立的功能片斷。通過(guò)對(duì)所有單獨(dú)部分的行為建立起信心,確信它們都和我們的期望一致;然后,我們才能開(kāi)始組裝和測(cè)試整個(gè)系統(tǒng)。

畢竟,要是我們對(duì)手上正在寫(xiě)的代碼的行為是否和我們的期望一致都沒(méi)把握,那么其他形式的測(cè)試也都只能是浪費(fèi)時(shí)間而已。在單元測(cè)試之后,你還需要其他形式的測(cè)試,有可能是更正規(guī)的測(cè)試,那一切都要看環(huán)境的需要來(lái)決定了?傊鰷y(cè)試如同做善事,總是要從家(代碼基本的正確性)開(kāi)始。
3.       為什么要使用單元測(cè)試

單元測(cè)試不但會(huì)使你的工作完成得更輕松,而且會(huì)令你的設(shè)計(jì)變得更好,甚至大大減少你花在調(diào)試上面的時(shí)間。

在我們上面的小故事里面,Pat 因?yàn)榧僭O(shè)底層的代碼是正確無(wú)誤的而卷入麻煩之中,先是高層代碼中使用了底層代碼;然后這些高層代碼又被更高層的代碼所使用,如此往復(fù)。在對(duì)這些代碼的行為沒(méi)有任何信心的前提下,Pat 等于是在假設(shè)上面用豎立卡片堆砌了一間房子——只要將下面卡片輕輕移動(dòng),整間房子會(huì)轟然倒塌。

當(dāng)基本的底層代碼不再可靠時(shí),那么必需的改動(dòng)無(wú)法只局限在底層。雖然你可以修正底層的問(wèn)題,但是這些對(duì)底層代碼的修改必然會(huì)影響到高層代碼,于是高層代碼也連帶地需要修改;以此遞推,很可能會(huì)動(dòng)到更高層的代碼。于是,一個(gè)對(duì)底層代碼的修正,可能會(huì)導(dǎo)致對(duì)幾乎所有代碼的一連串改動(dòng),從而使修改越來(lái)越多,也越來(lái)越復(fù)雜。于是,整間由卡片堆成的房子由此倒塌,從而使整個(gè)項(xiàng)目也以失敗告終。

Pat 總是說(shuō):“這怎么可能呢?”或者“我實(shí)在想不明白為什么會(huì)這樣”。如果你發(fā)現(xiàn)自己有時(shí)候也會(huì)有這種想法,那么這通常是你對(duì)自己的代碼還缺乏足夠信心的表現(xiàn)——你并不能確認(rèn)哪些是工作正常的而哪些不是。

為了獲得Dale 所具有的那種對(duì)代碼的信心,你需要“詢(xún)問(wèn)”代碼究竟做了什么,并檢查所產(chǎn)生的結(jié)果是否確實(shí)和你所期望的一致。

這個(gè)簡(jiǎn)單的想法描述了單元測(cè)試的核心內(nèi)涵:這個(gè)簡(jiǎn)單有效的技術(shù)是為了令代碼變得更加完美。

軟件測(cè)試工具 | 聯(lián)系我們 | 投訴建議 | 誠(chéng)聘英才 | 申請(qǐng)使用列表 | 網(wǎng)站地圖
滬ICP備07036474 2003-2017 版權(quán)所有 上海澤眾軟件科技有限公司 Shanghai ZeZhong Software Co.,Ltd