Junit簡介
為什么要進行單測試.
1.單元測試的目的
一個單元測試從整個系統(tǒng)中單獨檢驗產(chǎn)品程序代碼的『一個單元』并檢查其得到的結(jié)果是否是預(yù)期的。要測試的『一個單元』其大小是依據(jù)一組連貫的功能的大小及介于一個類別及一個包(package)之間實際上的變化(varies)。其目的是在整合程序代碼到系統(tǒng)的其余部分之前先測試以便找出程序代碼中的臭蟲(bugs)。Junit等支持在Java程序代碼中撰寫單元測試。
在整合之前于系統(tǒng)其它部分隔離起來抓蟲的理由是因為那是比較容易的找到臭蟲(亦即比較快且便宜)及比較容易修正問題(并顯示其解決方式是可行的)。
單元測試對于在初始整合一小部分程序代碼以及整合其余的改變之前提供了一些利益。如果有人需要變動現(xiàn)有的程序代碼,事實上單元測試仍然可以讓他對于其最后的程序代碼更有信心;即他的改變不會破壞任何東西。愈好的單元測試讓人愈有信心--理想上測試必須在加入的新功能前也隨之更新。
2.誰來撰寫單元測試及何時撰寫單元測試
程序代碼測試可能是非常乏味的,尤其是測試別人的程序,而當你是一個程序設(shè)計師的時候尤甚。但程序設(shè)計師喜歡撰寫程序,因此為什么不讓程序設(shè)計師撰寫一些程序可以作為測試之用呢?
當單元測試正確的實作可以幫助程序設(shè)計師變的更有生產(chǎn)力,而同時提升開發(fā)程序代碼的品質(zhì)。有一點你必須了解的是單元測試應(yīng)該是開發(fā)程序的一部份是很重要的;而且程序代碼的設(shè)計必須是可以測試的。目前的趨勢是在撰寫程序代碼之前要先撰寫單元測試,并且把焦點放在Java類別的接口及行為上。
先寫測試,再寫代碼的好處:
從技術(shù)上強制設(shè)計師先考慮一個類的功能,也就是這個類提供給外部的接口,而不至于太早陷入它的細節(jié)。這是面向?qū)ο筇岢囊环N設(shè)計原則。
好的測試其實就是一個好的文檔,這個類使用者往往可以通過查看這個類的測試代碼了解它的功能。特別的,如果你拿到別人的一個程序,對他寫測試是最好的了解這個程序的功能的方法。xp的原則是makeitsimple,不是很推薦另外寫文檔,因為項目在開發(fā)過程中往往處于變動中,如果在早期寫文檔,以后代碼變動后還得同步文檔,多了一個工作,而且由于項目時間緊往往文檔寫的不全或與代碼不一致,與其這樣,不如不寫。而如果在項目結(jié)束后再寫文檔,開發(fā)人員往往已經(jīng)忘記當時寫代碼時的種種考慮,況且有下一個項目的壓力,管理人員也不愿意再為舊的項目寫文檔。導(dǎo)致以后維護的問題
沒有人能保證需求不變動,以往項目往往對需求的變動大為頭疼,害怕這個改動會帶來其它地方的錯誤。為此,除了設(shè)計好的結(jié)構(gòu)以分割項目外(松耦合),但如果有了測試,并已經(jīng)建立了一個好的測試框架,對于需求的變動,修改完代碼后,只要重新運行測試代碼,如果測試通過,也就保證了修改的成功,如果測試中出現(xiàn)錯誤,也會馬上發(fā)現(xiàn)錯在哪里。修改相應(yīng)的部分,再運行測試,直至測試完全通過。
3.單元測試設(shè)計原則
保證一個模塊中的所有獨立路徑至少被執(zhí)行一次;
對所有的邏輯值均需要測試真、假兩個分支;
在上下邊界及可操作范圍內(nèi)運行所有循環(huán);
檢查內(nèi)部數(shù)據(jù)結(jié)構(gòu)以確保其有效性。
軟件公司里往往存在開發(fā)部門和測試部門之間的矛盾:由于開發(fā)和測試分為兩個部門,多了一層溝通的成本和時間,溝通往往會產(chǎn)生錯誤的發(fā)生。而且極易形成一個怪圈:開發(fā)人員為了趕任務(wù),寫了爛爛的代碼,就把它扔給測試人員,然后寫其它的任務(wù),測試當然是失敗的,又把代碼拿回去重寫,測試就成了一個很頭疼的問題。這種怪圈的根源是責(zé)任不清,根據(jù)xp中的規(guī)定:寫這個代碼的人必須為自己的代碼寫測試,而且只有測試通過,才算完成這個任務(wù)(這里的測試包括所有的測試,如果測試時發(fā)現(xiàn)由于你的程序?qū)е聞e的組的測試失敗,你有責(zé)任通知相關(guān)人員修改直至集成測試通過),這樣就可以避免這類問題的發(fā)生。
簡而言之,如果程序設(shè)計師要寫一段代碼:
先用junit寫測試,然后再寫代碼;
寫完代碼,運行測試,如果測試失敗,
修改代碼,運行測試,直到測試成功。
如果以后對程序進行修改,優(yōu)化(refactoring),只要再運行測試代碼。如果所有的測試都成功,則代碼修改完成。
3.單元測試與JavaTeam開發(fā)的結(jié)合
Java下的team開發(fā),一般采用cvs(版本控制)+ant(項目管理)+junit(單元測試、集成測試)的模式:
每天早上上班,每個開發(fā)人員從cvsserver獲取一個整個項目的工作拷貝。
拿到自己的任務(wù),先用junit寫今天的任務(wù)的測試代碼。
然后寫今天任務(wù)的代碼,運行測試(單元測試),直到測試通過。
任務(wù)完成在下班前一兩個小時,各個開發(fā)人員把任務(wù)提交到cvsserver。
然后由主管對整個項目運行自動測試(集成測試),哪個測試出錯,就找相關(guān)人員修改,直到所有測試通過。下班...
4.測試控制工具中要有甚么?
無論誰來撰寫單元測試或何時撰寫單元測試,我們的焦點應(yīng)該放在檢驗程序代碼;主要是在于產(chǎn)生錯誤的風(fēng)險。如果設(shè)計文件包含被測試對象的使用情節(jié);便可成為好的測試來源。不管如何,這些情節(jié)寫得不是很明確;因為這些情節(jié)實際上是以設(shè)計觀點所寫的--因此適當?shù)臏y試應(yīng)該有對等的情節(jié),換句話說,也就是測試設(shè)計應(yīng)該盡可能的包含用戶實際使用程序時可能產(chǎn)生的動作或者過程。
另一個測試案例好的來源是在整合后從產(chǎn)品程序代碼當中找到的問題,維修問題的處理方式往往值得封裝成為測試案例。
5.為什么要使用Junit等工具呢?
前面的論述說明為什么我們需要測試控制工具,但為什么我們使用Junit這些工具呢?
首先,完全Free。
第二點,使用方便。
在你提升程序代碼的品質(zhì)時JUnit測試仍允許你更快速的撰寫程序
那聽起來似乎不是很直覺,但那是事實。當你使用JUnit撰寫測試,你將花更少的時間除蟲,同時對你程序代碼的改變更俱有信心。這個信心讓你更積極重整程序代碼并增加新的功能。沒有測試,對于重整及增加新功能你會變得沒有信心;因為你不知道有甚么東西會產(chǎn)出的結(jié)果。采用一個綜合的測試系列,你可以在改變程序代碼之后快速的執(zhí)行多個測試并對于你的變動并未破壞任何東西感到有信心。在執(zhí)行測試時如果發(fā)現(xiàn)臭蟲,原始碼仍然清楚的在你腦中,因此很容易找到臭蟲。在JUnit中撰寫的測試幫助你以一種極大(extreme)的步伐撰寫程序及快速的找出缺點。
JUnit非常簡單
撰寫測試應(yīng)該很簡單--這是重點!如果撰寫測試太復(fù)雜或太耗時間,便無法要求程序設(shè)計師撰寫測試。使用JUnit你可以快速的撰寫測試并檢測你的程序代碼并逐步隨著程序代碼的成長增加測試。只要你寫了一些測試,你想要快速并頻繁的執(zhí)行測試而不至于中斷建立設(shè)計及開發(fā)程序。使用JUnit執(zhí)行測試就像編譯你的程序代碼那么容易。事實上,你應(yīng)該執(zhí)行編譯時也執(zhí)行測試。編譯是檢測程序代碼的語法而測試是檢查程序代碼的完整性(integrity)。
JUnit測試檢驗其結(jié)果并提供立即的回饋。
如果你是以人工比對測試的期望與實際結(jié)果那么測試是很不好玩的,而且讓你的速度慢下來。JUnit測試可以自動執(zhí)行并且檢查他們自己的結(jié)果。當你執(zhí)行測試,你獲得簡單且立即的回饋;比如測試是通過或失敗。而不再需要人工檢查測試結(jié)果的報告。
JUnit測試可以合成一個測試系列的層級架構(gòu)。
JUnit可以把測試組織成測試系列;這個測試系列可以包含其它的測試或測試系列。JUnit測試的合成行為允許你組合多個測試并自動的回歸(regression)從頭到尾測試整個測試系列。你也可以執(zhí)行測試系列層級架構(gòu)中任何一層的測試。
撰寫JUnit測試所費不多。
使用Junit測試框架,你可以很便宜的撰寫測試并享受由測試框架所提供的信心。撰寫一個測試就像寫一個方法一樣簡單;測試是檢驗要測試的程序代碼并定義期望的結(jié)果。這個測試框架提供自動執(zhí)行測試的背景;這個背景并成為其它測試集合的一部份。在測試少量的投資將持續(xù)讓你從時間及品質(zhì)中獲得回收。
JUnit測試提升軟件的穩(wěn)定性。
你寫的測試愈少;你的程序代碼變的愈不穩(wěn)定。測試使得軟件穩(wěn)定并逐步累積信心;因為任何變動不會造成漣漪效應(yīng)而漫及整個軟件。測試可以形成軟件的完整結(jié)構(gòu)的膠結(jié)。
JUnit測試是開發(fā)者測試。
JUnit測試是高度區(qū)域性(localized)測試;用以改善開發(fā)者的生產(chǎn)力及程序代碼品質(zhì)。不像功能測試(functiontest)視系統(tǒng)為一個黑箱以確認軟件整體的工作性為主,單元測試是由內(nèi)而外測試系統(tǒng)基礎(chǔ)的建構(gòu)區(qū)塊。開發(fā)者撰寫并擁有JUnit測試。每當一個開發(fā)反復(fù)(iteration)完成,這個測試便包裹成為交付軟件的一部份提供一種溝通的方式,「這是我交付的軟件并且是通過測試的。」
單元測試設(shè)計原則
保證一個模塊中的所有獨立路徑至少被執(zhí)行一次;
對所有的邏輯值均需要測試真、假兩個分支;
在上下邊界及可操作范圍內(nèi)運行所有循環(huán);
檢查內(nèi)部數(shù)據(jù)結(jié)構(gòu)以確保其有效性
JUnit測試是以Java寫成的。
使用Java測試Java軟件形成一個介于測試及程序代碼間的無縫(seamless)邊界。在測試的控制下測試變成整個軟件的擴充同時程序代碼可以被重整。Java編譯器的單元測試靜態(tài)語法檢查可已幫助測試程序并且確認遵守軟件接口的約定。
一段測試的程序代碼無法單獨的執(zhí)行,它需要是執(zhí)行環(huán)境的一部份。同時,它需要自動執(zhí)行的單元測試--譬如在系統(tǒng)中周期性的執(zhí)行所有的測試以證明沒有任何東西被破壞。由于單元測試需要符合特定的準則:一個成功的測試不應(yīng)該是人工檢查的(那可要到天荒地老了?。?,一個未通過測試的失敗應(yīng)可以產(chǎn)出文件以供診斷修改。而Junit可以提供給我們這些便利.。這樣所有測試開發(fā)者所需撰寫的只是測試碼本身了。跟optimizeit、Jtest那些昂貴而又超級麻煩的tool比較起來,其利昭然可見!
下面是如何在實際運用中使用單元測試.
eclipse3.1以上版本中都包含了Junit,可以直接使用.
給出一個簡單的測試實例
HelloWorld.java
publicclassHelloWorld{
publicHelloWorld(){
super();
//TODOAuto-generatedconstructorstub
}
publicStringsay()
{
return"HelloWorld!";
}
publicstaticvoidmain(String[]args){
//TODOAuto-generatedmethodstub
}
}
TestHelloWorld.java
importjunit.framework.TestCase;
publicclassTestHelloWorldextendsTestCase{
publicTestHelloWorld(Stringname)
{
super(name);
}
publicvoidtestSay(){
HelloWorldhi=newHelloWorld();
assertEquals("HelloWorld!",hi.say());
}
publicstaticvoidmain(String[]args){
junit.textui.TestRunner.run(TestHelloWorld.class);
}
}
愛華網(wǎng)


