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