在本篇文章中我們將介紹軟件工程師都可以使用的12個(gè)單元測(cè)試技巧,適用于任何編程語(yǔ)言和編程環(huán)境。

1、使用單元測(cè)試降低風(fēng)險(xiǎn)

新手可能會(huì)問(wèn)“為什么我應(yīng)該編寫(xiě)測(cè)試代碼?”的確,很多人會(huì)這樣想:測(cè)試工作不是應(yīng)該由進(jìn)行驗(yàn)收工作的測(cè)試人員來(lái)完成嗎?這種想法在現(xiàn)代軟件工程學(xué)中已經(jīng)沒(méi)有立足之地。軟件團(tuán)隊(duì)的目標(biāo)是開(kāi)發(fā)高質(zhì)量的軟件。無(wú)論是個(gè)人用戶(hù),還是企業(yè)用戶(hù),已經(jīng)無(wú)法接受上世紀(jì)80年代和90年代充滿(mǎn)漏洞的軟件。
現(xiàn)在你可以使用豐富的類(lèi)庫(kù)資源、Web服務(wù)和支持重構(gòu)及單元測(cè)試的綜合開(kāi)發(fā)環(huán)境,在軟件中再出現(xiàn)漏洞就沒(méi)有任何借口可找了。
單元測(cè)試背后的思想是,為每一個(gè)軟件單元、模塊和構(gòu)建創(chuàng)建一個(gè)測(cè)試代碼。單元測(cè)試讓軟件持續(xù)測(cè)試變得很簡(jiǎn)單;與手動(dòng)測(cè)試不同,你可以輕松的重復(fù)執(zhí)行單元測(cè)試。
隨著你的軟件規(guī)模變大,單元測(cè)試部分也隨之變大。每一個(gè)測(cè)試都是系統(tǒng)正常運(yùn)行的保障。代碼中存在漏洞就意味著軟件具有潛在風(fēng)險(xiǎn)。通過(guò)利用一系列單元測(cè)試,開(kāi)發(fā)者可以大大降低漏洞的數(shù)量,降低未經(jīng)實(shí)際運(yùn)行驗(yàn)證的程序的風(fēng)險(xiǎn)。

2、為每一個(gè)主要構(gòu)件編寫(xiě)一個(gè)測(cè)試用例

當(dāng)人們開(kāi)始使用單元測(cè)試時(shí),常常會(huì)先問(wèn)“我應(yīng)該編寫(xiě)什么測(cè)試?”
人們最初的想法可能是要編寫(xiě)大量的功能測(cè)試,也就是對(duì)系統(tǒng)不同的功能進(jìn)行測(cè)試驗(yàn)證。其實(shí)這種想法這是不對(duì)的。正確的做法應(yīng)該是為每一個(gè)主要構(gòu)件創(chuàng)建一個(gè)測(cè)試用例。
測(cè)試的重點(diǎn)應(yīng)該是一個(gè)構(gòu)件。在每一個(gè)構(gòu)件內(nèi)找到它的所有接口,也就是這個(gè)組件對(duì)外公開(kāi)的方法集。然后你才應(yīng)該為每一個(gè)公開(kāi)的方法編寫(xiě)一個(gè)測(cè)試。

3、創(chuàng)建抽象測(cè)試用例和添加測(cè)試工具

無(wú)論任何程序,都有一些共性的東西需要你對(duì)其進(jìn)行測(cè)試。那么你首先應(yīng)該為你的語(yǔ)言尋找一個(gè)單元測(cè)試。
舉個(gè)例子來(lái)說(shuō),很多Java開(kāi)發(fā)者使用Junit來(lái)進(jìn)行單元測(cè)試,它是一個(gè)簡(jiǎn)單但強(qiáng)大的測(cè)試框架。它具有一個(gè)TestCase類(lèi),是所有測(cè)試的基類(lèi)。
在你的開(kāi)發(fā)環(huán)境中增加方便的方法和可用的工具。這樣所有你的測(cè)試用例可以具有共同的基礎(chǔ)構(gòu)架,維護(hù)起來(lái)就非常容易。

4、編寫(xiě)敏捷測(cè)試

測(cè)試工作非常耗時(shí),因此請(qǐng)確保你的測(cè)試是有效的。好的測(cè)試應(yīng)該針對(duì)每個(gè)模塊的核心功能,而不是事無(wú)巨細(xì)挨個(gè)測(cè)試。
舉個(gè)例子來(lái)說(shuō),你沒(méi)有理由來(lái)為Java Bean的Setter和getter方法來(lái)單獨(dú)編寫(xiě)測(cè)試代碼,因?yàn)樗鼈兛隙〞?huì)測(cè)試中被涉及到的。
相反,你應(yīng)該針對(duì)軟件系統(tǒng)的行為來(lái)編寫(xiě)測(cè)試代碼。你不需要面面俱到;為現(xiàn)在想到的東西先創(chuàng)建測(cè)試,然后想到別的再回來(lái)增加更多測(cè)試。

5、為每一個(gè)測(cè)試創(chuàng)造干凈的環(huán)境

軟件工程師們總是很在乎效率,視效率如生命。因此如果你告訴他們,每一個(gè)測(cè)試需要單獨(dú)創(chuàng)建的話(huà),他們會(huì)認(rèn)為比較浪費(fèi)時(shí)間。
然而這一點(diǎn)是非常重要的,如果一個(gè)測(cè)試因?yàn)槭褂昧艘恍┢渌鼫y(cè)試的老數(shù)據(jù)而失敗,顯然這是你最不想發(fā)生的事情。因此請(qǐng)確保每一個(gè)測(cè)試被正確的創(chuàng)建,而不要擔(dān)心所謂的效率。
如果你所有的測(cè)試具有一個(gè)共同的環(huán)境,它并不隨著測(cè)試的運(yùn)行而改變,那么你可以在你的測(cè)試基類(lèi)中增加一個(gè)靜態(tài)的創(chuàng)建區(qū)。

6、使用模擬對(duì)象(Mock Objects)進(jìn)行有效測(cè)試

建立測(cè)試并不總是一件簡(jiǎn)單的事情,在有些時(shí)候你的第一感覺(jué)往往是沒(méi)有辦法進(jìn)行測(cè)試。
舉個(gè)例子來(lái)說(shuō),如果在你的程序中使用了Amazon Web服務(wù),如何在不影響真實(shí)系統(tǒng)的前提下在測(cè)試中模仿它呢?
其實(shí)有很多方法可用。你可以創(chuàng)建一些虛假的數(shù)據(jù),然后在測(cè)試中使用它們。在有用戶(hù)的系統(tǒng)中,可以創(chuàng)建一系列專(zhuān)門(mén)用于測(cè)試的賬號(hào)。
對(duì)一個(gè)生產(chǎn)系統(tǒng)進(jìn)行測(cè)試是一件非常危險(xiǎn)的做法:如果發(fā)生點(diǎn)什么錯(cuò)誤,你可能會(huì)誤刪真正的用戶(hù)數(shù)據(jù)。一個(gè)可行的辦法就是使用假數(shù)據(jù),又叫做模擬對(duì)象(stubs or mock objects)。
模擬對(duì)象實(shí)現(xiàn)了特定的接口,但是返回預(yù)先定義好的結(jié)果。舉個(gè)例子來(lái)說(shuō),你可以為Amazon S3創(chuàng)建一個(gè)模擬對(duì)象,它只從你的本地硬盤(pán)中讀取預(yù)先設(shè)置好的數(shù)據(jù),而不去使用真實(shí)服務(wù)數(shù)據(jù)。
在對(duì)具有很多構(gòu)件的復(fù)雜系統(tǒng)進(jìn)行測(cè)試的時(shí)候,模擬對(duì)象是非常有用的。在JavaScript中有幾個(gè)框架可以非常方便的創(chuàng)建模擬對(duì)象,其中最出名的是JMock。

7、代碼重構(gòu)時(shí)也對(duì)測(cè)試代碼進(jìn)行重構(gòu)

你只有對(duì)測(cè)試工作真正投入,它才會(huì)發(fā)揮更大的作用。你不僅僅要編寫(xiě)測(cè)試,你還需要確保它們及時(shí)更新。當(dāng)為一個(gè)組件增加一個(gè)新方法時(shí),你需要同時(shí)增加一個(gè)或更多的相應(yīng)測(cè)試。同樣,如果你要?jiǎng)h除無(wú)用代碼的話(huà),也要?jiǎng)h除已經(jīng)不再有用的測(cè)試。
在進(jìn)行大量重構(gòu)工作的時(shí)候單元測(cè)試尤其有用。利用重構(gòu)可以大大提高我們的編程效率,不過(guò)對(duì)代碼完成了重構(gòu)后,別忘了也對(duì)測(cè)試進(jìn)行相應(yīng)的修改,并要重新運(yùn)行一下所有相關(guān)測(cè)試,以確保在進(jìn)行程序改動(dòng)的時(shí)候沒(méi)有出現(xiàn)錯(cuò)誤。

8、針對(duì)發(fā)現(xiàn)的程序漏洞編寫(xiě)測(cè)試

在減少漏洞方面,單元測(cè)試是一個(gè)非常有用的武器。當(dāng)你發(fā)現(xiàn)了代碼中的問(wèn)題后,在對(duì)其進(jìn)行修復(fù)以前,先編寫(xiě)一個(gè)測(cè)試來(lái)讓這個(gè)問(wèn)題可以在測(cè)試的時(shí)候暴露出來(lái)。這樣,如果這個(gè)問(wèn)題在其它地方重新出現(xiàn)的話(huà),你就可以在測(cè)試的時(shí)候輕松發(fā)現(xiàn)它們。
這是一個(gè)非常有用的經(jīng)驗(yàn),因?yàn)槟悴豢赡芸偸邱R上就編寫(xiě)出能發(fā)現(xiàn)所有問(wèn)題的測(cè)試代碼。當(dāng)你增加了針對(duì)某種漏洞的測(cè)試后,實(shí)際上你的測(cè)試代碼距離完美又靠近了一步。

9、使用單元測(cè)試來(lái)確保性能

除了確保代碼的正確性之外,單元測(cè)試還可以幫助我們確保代碼的性能不會(huì)隨時(shí)間而下降。在很多系統(tǒng)中存在這個(gè)問(wèn)題,隨著系統(tǒng)開(kāi)發(fā)工作的繼續(xù)進(jìn)行,被加入了越來(lái)越多的代碼,會(huì)變得越來(lái)越慢。
要想編寫(xiě)性能測(cè)試,你需要在你的測(cè)試基類(lèi)中增加start和stop功能函數(shù)。在單元測(cè)試階段就開(kāi)始考慮性能測(cè)試是非常必要的,這樣在代碼發(fā)生改變或者對(duì)代碼進(jìn)行了優(yōu)化時(shí)就能看出這些改變是否會(huì)影響到性能,能盡早的發(fā)現(xiàn)代碼變更對(duì)性能的影響。
一個(gè)系統(tǒng)的性能如果拆分來(lái)看,可以看成若干單元性能的一個(gè)有機(jī)結(jié)合,單元的性能勢(shì)必也會(huì)對(duì)整個(gè)系統(tǒng)的性能產(chǎn)生影響,所以盡早考慮性能測(cè)試是很必要的,當(dāng)然這需要很好的分析和設(shè)計(jì)了。

10、為并發(fā)代碼創(chuàng)建測(cè)試

并發(fā)代碼通常不容易控制,通常是許多漏洞的源頭。因此對(duì)它們進(jìn)行單元測(cè)試是非常重要的。實(shí)現(xiàn)方法是使用一個(gè)休眠和鎖定機(jī)制。如果你需要等待一個(gè)特定的系統(tǒng)狀態(tài),你可以在你的測(cè)試中 使用休眠調(diào)用功能。
盡管這并不是一個(gè)完全正確的解決辦法,但是在很多情況下它已經(jīng)夠用了。
如果要在一個(gè)更加復(fù)雜的場(chǎng)景中模擬并發(fā)性,你需要圍繞你測(cè)試的對(duì)象進(jìn)行鎖的傳遞。這樣你可以模擬并發(fā)系統(tǒng),不過(guò)它是線(xiàn)性的。

11、連續(xù)運(yùn)行測(cè)試

軟件測(cè)試的要點(diǎn)就是多多運(yùn)行它們。尤其在大型開(kāi)發(fā)團(tuán)隊(duì)中,常常有數(shù)十個(gè)開(kāi)發(fā)者共同修改同一個(gè)程序,這種情況進(jìn)行連續(xù)的單元測(cè)試是非常重要的。
你可以每隔幾個(gè)小時(shí)運(yùn)行一次測(cè)試,也可以每次當(dāng)有代碼加入的時(shí)候運(yùn)行測(cè)試,或者每天運(yùn)行一次測(cè)試。根據(jù)自己的實(shí)際情況決定哪一種方法最適合你的項(xiàng)目,然后讓測(cè)試自動(dòng)連續(xù)運(yùn)行。

12、享受測(cè)試的樂(lè)趣

這可能是軟件測(cè)試中最重要的技巧。當(dāng)我第一次發(fā)現(xiàn)單元測(cè)試的時(shí)候,我懷疑它簡(jiǎn)直就是一件多此一舉的事情。但是我還是嘗試著接受了它,因?yàn)槲倚刨?lài)的一些優(yōu)秀程序員告訴我它非常有用。
技術(shù)大師Martin Fowler曾表示,單元測(cè)試能夠使你更快地完成工作。無(wú)數(shù)次的實(shí)踐已經(jīng)證明這一點(diǎn)。你的時(shí)間越是緊張,就越是要寫(xiě)單元測(cè)試,它看上去慢,但實(shí)際上能夠幫助你更快、更舒服地達(dá)到目標(biāo)。
單元測(cè)試可以讓你的大腦處于一種完全不同于編程時(shí)的狀態(tài)。為一個(gè)指定的構(gòu)件設(shè)計(jì)一個(gè)簡(jiǎn)單又正確的測(cè)試代碼是一件非常有意思的事情。
一旦你開(kāi)始編寫(xiě)測(cè)試,你會(huì)發(fā)現(xiàn)你已經(jīng)離不開(kāi)它。為了讓測(cè)試變得更有趣,你可以與別人進(jìn)行結(jié)對(duì)編程(pair programming)。無(wú)論你是與同伴一起編寫(xiě)測(cè)試,還是互相為對(duì)方編寫(xiě)測(cè)試,都可以體驗(yàn)到其中的樂(lè)趣。最終你將會(huì)非常高興的認(rèn)為你的系統(tǒng)可以真正運(yùn)行,因?yàn)樗ㄟ^(guò)了你的測(cè)試。

分享到

wangziyi

相關(guān)推薦