<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    posts - 80,comments - 749,trackbacks - 2

    {關(guān)鍵字}

    測(cè)試驅(qū)動(dòng)開(kāi)發(fā)/Test Driven Development/TDD
    測(cè)試用例/TestCase/TC
    設(shè)計(jì)/Design
    重構(gòu)/Refactoring

    {TDD的目標(biāo)}

    Clean Code That Works

    這句話的含義是,事實(shí)上我們只做兩件事情:讓代碼奏效(Work)和讓代碼潔凈(Clean),前者是把事情做對(duì),后者是把事情做好。想想看,其實(shí) 我們平時(shí)所做的所有工作,除去無(wú)用的工作和錯(cuò)誤的工作以外,真正正確的工作,并且是真正有意義的工作,其實(shí)也就只有兩大類:增加功能和提升設(shè)計(jì),而TDD 正是在這個(gè)原則上產(chǎn)生的。如果您的工作并非我們想象的這樣,(這意味著您還存在第三類正確有意義的工作,或者您所要做的根本和我們?cè)谡f(shuō)的是兩回事),那么 這告訴我們您并不需要TDD,或者不適用TDD。而如果我們偶然猜對(duì)(這對(duì)于我來(lái)說(shuō)是偶然,而對(duì)于Kent Beck和Martin Fowler這樣的大師來(lái)說(shuō)則是辛勤工作的成果),那么恭喜您,TDD有可能成為您顯著提升工作效率的一件法寶。請(qǐng)不要將信將疑,若即若離,因?yàn)槿魏我豁?xiàng) 新的技術(shù)——只要是從根本上改變?nèi)说男袨榉绞降募夹g(shù)——就必然使得相信它的人越來(lái)越相信,不信的人越來(lái)越不信。這就好比學(xué)游泳,唯一能學(xué)會(huì)游泳的途徑就是 親自下去游,除此之外別無(wú)他法。這也好比成功學(xué),即使把卡耐基或希爾博士的書倒背如流也不能擁有積極的心態(tài),可當(dāng)你以積極的心態(tài)去成就了一番事業(yè)之后,你 就再也離不開(kāi)它了。相信我,TDD也是這樣!想試用TDD的人們,請(qǐng)遵循下面的步驟:

    編寫TestCase --> 實(shí)現(xiàn)TestCase --> 重構(gòu)
    (確定范圍和目標(biāo))   (增加功能)   (提升設(shè)計(jì))

    [友情提示:敏捷建模中的一個(gè)相當(dāng)重要的實(shí)踐被稱為:Prove it With Code,這種想法和TDD不謀而合。]

    {TDD的優(yōu)點(diǎn)}

      『充滿吸引力的優(yōu)點(diǎn)』

    1. 完工時(shí)完工。表明我可以很清楚的看到自己的這段工作已經(jīng)結(jié)束了,而傳統(tǒng)的方式很難知道什么時(shí)候編碼工作結(jié)束了。
    2. 全面正確的認(rèn)識(shí)代碼和利用代碼,而傳統(tǒng)的方式?jīng)]有這個(gè)機(jī)會(huì)。
    3. 為利用你成果的人提供Sample,無(wú)論它是要利用你的源代碼,還是直接重用你提供的組件。
    4. 開(kāi)發(fā)小組間降低了交流成本,提高了相互信賴程度。
    5. 避免了過(guò)渡設(shè)計(jì)。
    6. 系統(tǒng)可以與詳盡的測(cè)試集一起發(fā)布,從而對(duì)程序的將來(lái)版本的修改和擴(kuò)展提供方便。
    7. TDD給了我們自信,讓我們今天的問(wèn)題今天解決,明天的問(wèn)題明天解決,今天不能解決明天的問(wèn)題,因?yàn)槊魈斓膯?wèn)題還沒(méi)有出現(xiàn)(沒(méi)有TestCase),除非有TestCase否則我決不寫任何代碼;明天也不必?fù)?dān)心今天的問(wèn)題,只要我亮了綠燈。

      『不顯而易見(jiàn)的優(yōu)點(diǎn)』

    8. 逃避了設(shè)計(jì)角色。對(duì)于一個(gè)敏捷的開(kāi)發(fā)小組,每個(gè)人都在做設(shè)計(jì)。
    9. 大部分時(shí)間代碼處在高質(zhì)量狀態(tài),100%的時(shí)間里成果是可見(jiàn)的。
    10. 由于可以保證編寫測(cè)試和編寫代碼的是相同的程序員,降低了理解代碼所花費(fèi)的成本。
    11. 為減少文檔和代碼之間存在的細(xì)微的差別和由這種差別所引入的Bug作出杰出貢獻(xiàn)。
    12. 在預(yù)先設(shè)計(jì)和緊急設(shè)計(jì)之間建立一種平衡點(diǎn),為你區(qū)分哪些設(shè)計(jì)該事先做、哪些設(shè)計(jì)該迭代時(shí)做提供了一個(gè)可靠的判斷依據(jù)。

      『有爭(zhēng)議的優(yōu)點(diǎn)』

    13. 事實(shí)上提高了開(kāi)發(fā)效率。每一個(gè)正在使用TDD并相信TDD的人都會(huì)相信這一點(diǎn),但觀望者則不同,不相信TDD的人甚至堅(jiān)決反對(duì)這一點(diǎn),這很正常,世界總是這樣。
    14. 發(fā)現(xiàn)比傳統(tǒng)測(cè)試方式更多的Bug。
    15. 使IDE的調(diào)試功能失去意義,或者應(yīng)該說(shuō),避免了令人頭痛的調(diào)試和節(jié)約了調(diào)試的時(shí)間。
    16. 總是處在要么編程要么重構(gòu)的狀態(tài)下,不會(huì)使人抓狂。(兩頂帽子)
    17. 單元測(cè)試非常有趣。

    {TDD的步驟}
    編寫TestCase --> 實(shí)現(xiàn)TestCase --> 重構(gòu)
    (不可運(yùn)行)   (可運(yùn)行)   (重構(gòu))
    步驟 制品
    (1)快速新增一個(gè)測(cè)試用例 新的TestCase
    (2)編譯所有代碼,剛剛寫的那個(gè)測(cè)試很可能編譯不通過(guò) 原始的TODO List
    (3)做盡可能少的改動(dòng),讓編譯通過(guò) Interface
    (4)運(yùn)行所有的測(cè)試,發(fā)現(xiàn)最新的測(cè)試不能編譯通過(guò) -(Red Bar)
    (5)做盡可能少的改動(dòng),讓測(cè)試通過(guò) Implementation
    (6)運(yùn)行所有的測(cè)試,保證每個(gè)都能通過(guò) -(Green Bar)
    (7)重構(gòu)代碼,以消除重復(fù)設(shè)計(jì) Clean Code That Works

    {FAQ}

    [什么時(shí)候重構(gòu)?]
    如果您在軟件公司工作,就意味著您成天都會(huì)和想通過(guò)重構(gòu)改善代碼質(zhì)量的想法打交道,不僅您如此,您的大部 分同事也都如此。可是,究竟什么時(shí)候該重構(gòu),什么情況下應(yīng)該重構(gòu)呢?我相信您和您的同事可能有很多不同的看法,最常見(jiàn)的答案是“該重構(gòu)時(shí)重構(gòu)”,“寫不下 去的時(shí)候重構(gòu)”,和“下一次迭代開(kāi)始之前重構(gòu)”,或者干脆就是“最近沒(méi)時(shí)間,就不重構(gòu)了,下次有時(shí)間的時(shí)候重構(gòu)吧”。正如您已經(jīng)預(yù)見(jiàn)到我想說(shuō)的——這些想 法都是對(duì)重構(gòu)的誤解。重構(gòu)不是一種構(gòu)建軟件的工具,不是一種設(shè)計(jì)軟件的模式,也不是一個(gè)軟件開(kāi)發(fā)過(guò)程中的環(huán)節(jié),正確理解重構(gòu)的人應(yīng)該把重構(gòu)看成一種書寫代 碼的方式,或習(xí)慣,重構(gòu)時(shí)時(shí)刻刻有可能發(fā)生。在TDD中,除去編寫測(cè)試用例和實(shí)現(xiàn)測(cè)試用例之外的所有工作都是重構(gòu),所以,沒(méi)有重構(gòu)任何設(shè)計(jì)都不能實(shí)現(xiàn)。至 于什么時(shí)候重構(gòu)嘛,還要分開(kāi)看,有三句話是我的經(jīng)驗(yàn):實(shí)現(xiàn)測(cè)試用例時(shí)重構(gòu)代碼,完成某個(gè)特性時(shí)重構(gòu)設(shè)計(jì),產(chǎn)品的重構(gòu)完成后還要記得重構(gòu)一下測(cè)試用例哦。

    [什么時(shí)候設(shè)計(jì)?]
    這個(gè)問(wèn)題比前面一個(gè)要難回答的多,實(shí)話實(shí)說(shuō),本人在依照TDD開(kāi)發(fā)軟件的時(shí)候也常常被這個(gè)問(wèn)題困擾,總是 覺(jué)得有些問(wèn)題應(yīng)該在寫測(cè)試用例之前定下來(lái),而有些問(wèn)題應(yīng)該在新增一個(gè)一個(gè)測(cè)試用例的過(guò)程中自然出現(xiàn),水到渠成。所以,我的建議是,設(shè)計(jì)的時(shí)機(jī)應(yīng)該由開(kāi)發(fā)者 自己把握,不要受到TDD方式的限制,但是,不需要事先確定的事一定不能事先確定,免得捆住了自己的手腳。

    [什么時(shí)候增加新的TestCase?]
    沒(méi)事做的時(shí)候。通常我們認(rèn)為,如果你要增加一個(gè)新的功能,那么先寫一個(gè)不能通過(guò)的 TestCase;如果你發(fā)現(xiàn)了一個(gè)bug,那么先寫一個(gè)不能通過(guò)的TestCase;如果你現(xiàn)在什么都沒(méi)有,從0開(kāi)始,請(qǐng)先寫一個(gè)不能通過(guò)的 TestCase。所有的工作都是從一個(gè)TestCase開(kāi)始。此外,還要注意的是,一些大師要求我們每次只允許有一個(gè)TestCase亮紅燈,在這個(gè) TestCase沒(méi)有Green之前不可以寫別的TestCase,這種要求可以適當(dāng)考慮,但即使有多個(gè)TestCase亮紅燈也不要緊,并未違反TDD 的主要精神。

    [TestCase該怎么寫?]
    測(cè)試用例的編寫實(shí)際上就是兩個(gè)過(guò)程:使用尚不存在的代碼和定義這些代碼的執(zhí)行結(jié)果。所以一個(gè) TestCase也就應(yīng)該包括兩個(gè)部分——場(chǎng)景和斷言。第一次寫TestCase的人會(huì)有很大的不適應(yīng)的感覺(jué),因?yàn)槟阒八鶎懙乃袞|西都是在解決問(wèn)題, 現(xiàn)在要你提出問(wèn)題確實(shí)不大習(xí)慣,不過(guò)不用擔(dān)心,你正在做正確的事情,而這個(gè)世界上最難的事情也不在于如何解決問(wèn)題,而在于ask the right question!

    [TDD能幫助我消除Bug嗎?]
    答:不能!千萬(wàn)不要把“測(cè)試”和“除蟲”混為一談!“除蟲”是指程序員通過(guò)自己的努力來(lái)減 少bug的數(shù)量(消除bug這樣的字眼我們還是不要講為好^_^),而“測(cè)試”是指程序員書寫產(chǎn)品以外的一段代碼來(lái)確保產(chǎn)品能有效工作。雖然TDD所編寫 的測(cè)試用例在一定程度上為尋找bug提供了依據(jù),但事實(shí)上,按照TDD的方式進(jìn)行的軟件開(kāi)發(fā)是不可能通過(guò)TDD再找到bug的(想想我們前面說(shuō)的“完工時(shí) 完工”),你想啊,當(dāng)我們的代碼完成的時(shí)候,所有的測(cè)試用例都亮了綠燈,這時(shí)隱藏在代碼中的bug一個(gè)都不會(huì)露出馬腳來(lái)。

    但是,如果要問(wèn)“測(cè)試”和“除蟲”之間有什么聯(lián)系,我相信還是有很多話可以講的,比如TDD事實(shí)上減少了bug的數(shù)量,把查找bug戰(zhàn)役的關(guān)注點(diǎn)從 全線戰(zhàn)場(chǎng)提升到代碼戰(zhàn)場(chǎng)以上。還有,bug的最可怕之處不在于隱藏之深,而在于滿天遍野。如果你發(fā)現(xiàn)了一個(gè)用戶很不容易才能發(fā)現(xiàn)的bug,那么不一定對(duì)工 作做出了什么杰出貢獻(xiàn),但是如果你發(fā)現(xiàn)一段代碼中,bug的密度或離散程度過(guò)高,那么恭喜你,你應(yīng)該拋棄并重寫這段代碼了。TDD避免了這種情況,所以將 尋找bug的工作降低到了一個(gè)新的低度。

    [我該為一個(gè)Feature編寫TestCase還是為一個(gè)類編寫TestCase?]
    初學(xué)者常問(wèn)的問(wèn)題。雖然我們從TDD 的說(shuō)明書上看到應(yīng)該為一個(gè)特性編寫相應(yīng)的TestCase,但為什么著名的TDD大師所寫的TestCase都是和類/方法一一對(duì)應(yīng)的呢?為了解釋這個(gè)問(wèn) 題,我和我的同事們都做了很多試驗(yàn),最后我們得到了一個(gè)結(jié)論,雖然我不知道是否正確,但是如果您沒(méi)有答案,可以姑且相信我們。

    我們的研究結(jié)果表明,通常在一個(gè)特性的開(kāi)發(fā)開(kāi)始時(shí),我們針對(duì)特性編寫測(cè)試用例,如果您發(fā)現(xiàn)這個(gè)特性無(wú)法用TestCase表達(dá),那么請(qǐng)將這個(gè)特性細(xì) 分,直至您可以為手上的特性寫出TestCase為止。從這里開(kāi)始是最安全的,它不會(huì)導(dǎo)致任何設(shè)計(jì)上重大的失誤。但是,隨著您不斷的重構(gòu)代碼,不斷的重構(gòu) TestCase,不斷的依據(jù)TDD的思想做下去,最后當(dāng)產(chǎn)品伴隨測(cè)試用例集一起發(fā)布的時(shí)候,您就會(huì)不經(jīng)意的發(fā)現(xiàn)經(jīng)過(guò)重構(gòu)以后的測(cè)試用例很可能是和產(chǎn)品中 的類/方法一一對(duì)應(yīng)的。

    [什么時(shí)候應(yīng)該將全部測(cè)試都運(yùn)行一遍?]
    Good Question!大師們要求我們每次重構(gòu)之后都要完整的運(yùn)行一遍測(cè)試用例。這個(gè)要求可以理解,因?yàn)橹貥?gòu)很可能會(huì)改變整個(gè)代碼的結(jié)構(gòu)或設(shè)計(jì),從而導(dǎo)致不可 預(yù)見(jiàn)的后果,但是如果我正在開(kāi)發(fā)的是一個(gè)ERP怎么辦?運(yùn)行一遍完整的測(cè)試用例可能將花費(fèi)數(shù)個(gè)小時(shí),況且現(xiàn)在很多重構(gòu)都是由工具做到的,這個(gè)要求的可行性 和前提條件都有所動(dòng)搖。所以我認(rèn)為原則上你可以挑幾個(gè)你覺(jué)得可能受到本次重構(gòu)影響的TestCase去run,但是如果運(yùn)行整個(gè)測(cè)試包只要花費(fèi)數(shù)秒的時(shí) 間,那么不介意你按大師的要求去做。

    [什么時(shí)候改進(jìn)一個(gè)TestCase?]
    增加的測(cè)試用例或重構(gòu)以后的代碼導(dǎo)致了原來(lái)的TestCase的失去了效果,變得無(wú) 意義,甚至可能導(dǎo)致錯(cuò)誤的結(jié)果,這時(shí)是改進(jìn)TestCase的最好時(shí)機(jī)。但是有時(shí)你會(huì)發(fā)現(xiàn),這樣做僅僅導(dǎo)致了原來(lái)的TestCase在設(shè)計(jì)上是臃腫的,或 者是冗余的,這都不要緊,只要它沒(méi)有失效,你仍然不用去改進(jìn)它。記住,TestCase不是你的產(chǎn)品,它不要好看,也不要怎么太科學(xué),甚至沒(méi)有性能要求, 它只要能完成它的使命就可以了——這也證明了我們后面所說(shuō)的“用Ctrl-C/Ctrl-V編寫測(cè)試用例”的可行性。

    但是,美國(guó)人的想法其實(shí)跟我們還是不太一樣,拿托尼巴贊的MindMap來(lái)說(shuō)吧,其實(shí)畫MindMap只是為了表現(xiàn)自己的思路,或記憶某些重要的事 情,但托尼卻建議大家把MindMap畫成一件藝術(shù)品,甚至還有很多藝術(shù)家把自己畫的抽象派MindMap拿出來(lái)幫助托尼做宣傳。同樣,大師們也要求我們 把TestCase寫的跟代碼一樣質(zhì)量精良,可我想說(shuō)的是,現(xiàn)在國(guó)內(nèi)有幾個(gè)公司能把產(chǎn)品的代碼寫的精良??還是一步一步慢慢來(lái)吧。

    [為什么原來(lái)通過(guò)的測(cè)試用例現(xiàn)在不能通過(guò)了?]
    這是一個(gè)警報(bào),Red Alert!它可能表達(dá)了兩層意思——都不是什么好意思——1)你剛剛進(jìn)行的重構(gòu)可能失敗了,或存在一些錯(cuò)誤未被發(fā)現(xiàn),至少重構(gòu)的結(jié)果和原來(lái)的代碼不等價(jià) 了。2)你剛剛增加的TestCase所表達(dá)的意思跟前面已經(jīng)有的TestCase相沖突,也就是說(shuō),新增的功能違背了已有的設(shè)計(jì),這種情況大部分可能是 之前的設(shè)計(jì)錯(cuò)了。但無(wú)論哪錯(cuò)了,無(wú)論是那層意思,想找到這個(gè)問(wèn)題的根源都比TDD的正常工作要難。

    [我怎么知道那里該有一個(gè)方法還是該有一個(gè)類?]
    這個(gè)問(wèn)題也是常常出現(xiàn)在我的腦海中,無(wú)論你是第一次接觸TDD或者已經(jīng)成為 TDD專家,這個(gè)問(wèn)題都會(huì)纏繞著你不放。不過(guò)問(wèn)題的答案可以參考前面的“什么時(shí)候設(shè)計(jì)”一節(jié),答案不是唯一的。其實(shí)多數(shù)時(shí)候你不必考慮未來(lái),今天只做今天 的事,只要有重構(gòu)工具,從方法到類和從類到方法都很容易。

    [我要寫一個(gè)TestCase,可是不知道從哪里開(kāi)始?]
    從最重要的事開(kāi)始,what matters most?從腳下開(kāi)始,從手頭上的工作開(kāi)始,從眼前的事開(kāi)始。從一個(gè)沒(méi)有UI的核心特性開(kāi)始,從算法開(kāi)始,或者從最有可能耽誤時(shí)間的模塊開(kāi)始,從一個(gè)最嚴(yán) 重的bug開(kāi)始。這是TDD主義者和鼠目寸光者的一個(gè)共同點(diǎn),不同點(diǎn)是前者早已成竹在胸。

    [為什么我的測(cè)試總是看起來(lái)有點(diǎn)愚蠢?]
    哦?是嗎?來(lái),握個(gè)手,我的也是!不必?fù)?dān)心這一點(diǎn),事實(shí)上,大師們給的例子也相當(dāng)愚 蠢,比如一個(gè)極端的例子是要寫一個(gè)兩個(gè)int變量相加的方法,大師先斷言2+3=5,再斷言5+5=10,難道這些代碼不是很愚蠢嗎?其實(shí)這只是一個(gè)極端 的例子,當(dāng)你初次接觸TDD時(shí),寫這樣的代碼沒(méi)什么不好,以后當(dāng)你熟練時(shí)就會(huì)發(fā)現(xiàn)這樣寫沒(méi)必要了,要記住,謙虛是通往TDD的必經(jīng)之路!從經(jīng)典開(kāi)發(fā)方法轉(zhuǎn) 向TDD就像從面向過(guò)程轉(zhuǎn)向面向?qū)ο笠粯永щy,你可能什么都懂,但你寫出來(lái)的類沒(méi)有一個(gè)純OO的!我的同事還告訴我真正的太極拳,其速度是很快的,不比任 何一個(gè)快拳要慢,但是初學(xué)者(通常是指學(xué)習(xí)太極拳的前10年)太不容易把每個(gè)姿勢(shì)都做對(duì),所以只能慢慢來(lái)。

    [什么場(chǎng)合不適用TDD?]
    問(wèn)的好,確實(shí)有很多場(chǎng)合不適合使用TDD。比如對(duì)軟件質(zhì)量要求極高的軍事或科研產(chǎn)品——神州六號(hào),人命關(guān)天的軟件——醫(yī)療設(shè)備,等等,再比如設(shè)計(jì)很重要必須提前做好的軟件,這些都不適合TDD,但是不適合TDD不代表不能寫TestCase,只是作用不同,地位不同罷了。

    {Best Practise}

    [微笑面對(duì)編譯錯(cuò)誤]
    學(xué)生時(shí)代最害怕的就是編譯錯(cuò)誤,編譯錯(cuò)誤可能會(huì)被老師視為上課不認(rèn)真聽(tīng)課的證據(jù),或者同學(xué)間相互嘲笑的 砝碼。甚至離開(kāi)學(xué)校很多年的老程序員依然害怕它就像害怕遲到一樣,潛意識(shí)里似乎編譯錯(cuò)誤極有可能和工資掛鉤(或者和智商掛鉤,反正都不是什么好事)。其 實(shí),只要提交到版本管理的代碼沒(méi)有編譯錯(cuò)誤就可以了,不要擔(dān)心自己手上的代碼的編譯錯(cuò)誤,通常,編譯錯(cuò)誤都集中在下面三個(gè)方面:
    (1)你的代碼存在低級(jí)錯(cuò)誤
    (2)由于某些Interface的實(shí)現(xiàn)尚不存在,所以被測(cè)試代碼無(wú)法編譯
    (3)由于某些代碼尚不存在,所以測(cè)試代碼無(wú)法編譯
    請(qǐng)注意第二點(diǎn)與第三點(diǎn)完全不同,前者表明設(shè)計(jì)已存在,而實(shí)現(xiàn)不存在導(dǎo)致的編譯錯(cuò)誤;后者則指僅有TestCase而其它什么都沒(méi)有的情況,設(shè)計(jì)和實(shí)現(xiàn)都不存在,沒(méi)有Interface也沒(méi)有Implementation。

    另外,編譯器還有一個(gè)優(yōu)點(diǎn),那就是以最敏捷的身手告訴你,你的代碼中有那些錯(cuò)誤。當(dāng)然如果你擁有Eclipse這樣可以及時(shí)提示編譯錯(cuò)誤的IDE,就不需要這樣的功能了。

    [重視你的計(jì)劃清單]
    在非TDD的情況下,尤其是傳統(tǒng)的瀑布模型的情況下,程序員不會(huì)不知道該做什么,事實(shí)上,總是有設(shè)計(jì)或 者別的什么制品在引導(dǎo)程序員開(kāi)發(fā)。但是在TDD的情況下,這種優(yōu)勢(shì)沒(méi)有了,所以一個(gè)計(jì)劃清單對(duì)你來(lái)說(shuō)十分重要,因?yàn)槟惚仨氉约喊l(fā)現(xiàn)該做什么。不同性格的人 對(duì)于這一點(diǎn)會(huì)有不同的反應(yīng),我相信平時(shí)做事沒(méi)什么計(jì)劃要依靠別人安排的人(所謂將才)可能略有不適應(yīng),不過(guò)不要緊,Tasks和Calendar(又稱效 率手冊(cè))早已成為現(xiàn)代上班族的必備工具了;而平時(shí)工作生活就很有計(jì)劃性的人,比如我:),就會(huì)更喜歡這種自己可以掌控Plan的方式了。

    [廢黜每日代碼質(zhì)量檢查]
    如果我沒(méi)有記錯(cuò)的話,PSP對(duì)于個(gè)人代碼檢查的要求是蠻嚴(yán)格的,而同樣是在針對(duì)個(gè)人的問(wèn)題上, TDD卻建議你廢黜每日代碼質(zhì)量檢查,別起疑心,因?yàn)槟憧偸窃谧鯰estCase要求你做的事情,并且總是有辦法(自動(dòng)的)檢查代碼有沒(méi)有做到這些事情 ——紅燈停綠燈行,所以每日代碼檢查的時(shí)間可能被節(jié)省,對(duì)于一個(gè)嚴(yán)格的PSP實(shí)踐者來(lái)說(shuō),這個(gè)成本還是很可觀的!

    此外,對(duì)于每日代碼質(zhì)量檢查的另一個(gè)好處,就是幫助你認(rèn)識(shí)自己的代碼,全面的從宏觀、微觀、各個(gè)角度審視自己的成果,現(xiàn)在,當(dāng)你依照TDD做事時(shí),這個(gè)優(yōu)點(diǎn)也不需要了,還記得前面說(shuō)的TDD的第二個(gè)優(yōu)點(diǎn)嗎,因?yàn)槟阋呀?jīng)全面的使用了一遍你的代碼,這完全可以達(dá)到目的。

    但是,問(wèn)題往往也并不那么簡(jiǎn)單,現(xiàn)在有沒(méi)有人能告訴我,我如何全面審視我所寫的測(cè)試用例呢?別忘了,它們也是以代碼的形式存在的哦。呵呵,但愿這個(gè) 問(wèn)題沒(méi)有把你嚇到,因?yàn)槲蚁嘈诺侥壳盀橹梗€不是瓶頸問(wèn)題,況且在編寫產(chǎn)品代碼的時(shí)候你還是會(huì)自主的發(fā)現(xiàn)很多測(cè)試代碼上的沒(méi)考慮到的地方,可以就此修改 一下。道理就是如此,世界上沒(méi)有任何方法能代替你思考的過(guò)程,所以也沒(méi)有任何方法能阻止你犯錯(cuò)誤,TDD僅能讓你更容易發(fā)現(xiàn)這些錯(cuò)誤而已。

    [如果無(wú)法完成一個(gè)大的測(cè)試,就從最小的開(kāi)始]
    如果我無(wú)法開(kāi)始怎么辦,教科書上有個(gè)很好的例子:我要寫一個(gè)電影列表的類,我 不知道如何下手,如何寫測(cè)試用例,不要緊,首先想象靜態(tài)的結(jié)果,如果我的電影列表剛剛建立呢,那么它應(yīng)該是空的,OK,就寫這個(gè)斷言吧,斷言一個(gè)剛剛初始 化的電影列表是空的。這不是愚蠢,這是細(xì)節(jié),奧運(yùn)會(huì)五項(xiàng)全能的金牌得主瑪麗蓮·金是這樣說(shuō)的:“成功人士的共同點(diǎn)在于……如果目標(biāo)不夠清晰,他們會(huì)首先做 通往成功道路上的每一個(gè)細(xì)小步驟……”。

    [嘗試編寫自己的xUnit]
    Kent Beck建議大家每當(dāng)接觸一個(gè)新的語(yǔ)言或開(kāi)發(fā)平臺(tái)的時(shí)候,就自己寫這個(gè)語(yǔ)言或平臺(tái)的xUnit,其實(shí)幾乎所有常用的語(yǔ)言和平臺(tái)都已經(jīng)有了自己的 xUnit,而且都是大同小異,但是為什么大師給出了這樣的建議呢。其實(shí)Kent Beck的意思是說(shuō)通過(guò)這樣的方式你可以很快的了解這個(gè)語(yǔ)言或平臺(tái)的特性,而且xUnit確實(shí)很簡(jiǎn)單,只要知道原理很快就能寫出來(lái)。這對(duì)于那些喜歡自己寫 底層代碼的人,或者喜歡控制力的人而言是個(gè)好消息。

    [善于使用Ctrl-C/Ctrl-V來(lái)編寫TestCase]
    不必?fù)?dān)心TestCase會(huì)有代碼冗余的問(wèn)題,讓它冗余好了。

    [永遠(yuǎn)都是功能First,改進(jìn)可以稍后進(jìn)行]
    上面這個(gè)標(biāo)題還可以改成另外一句話:避免過(guò)渡設(shè)計(jì)!

    [淘汰陳舊的用例]
    舍不得孩子套不著狼。不要可惜陳舊的用例,因?yàn)樗鼈兛赡軓母拍钌弦呀?jīng)是錯(cuò)誤的了,或僅僅會(huì)得出錯(cuò)誤的結(jié)果,或者在某次重構(gòu)之后失去了意義。當(dāng)然也不一定非要?jiǎng)h除它們,從TestSuite中除去(JUnit)或加上Ignored(NUnit)標(biāo)簽也是一個(gè)好辦法。

    [用TestCase做試驗(yàn)]
    如果你在開(kāi)始某個(gè)特性或產(chǎn)品的開(kāi)發(fā)之前對(duì)某個(gè)領(lǐng)域不太熟悉或一無(wú)所知,或者對(duì)自己在該領(lǐng)域里的 能力一無(wú)所知,那么你一定會(huì)選擇做試驗(yàn),在有單元測(cè)試作工具的情況下,建議你用TestCase做試驗(yàn),這看起來(lái)就像你在寫一個(gè)驗(yàn)證功能是否實(shí)現(xiàn)的 TestCase一樣,而事實(shí)上也一樣,只不過(guò)你所驗(yàn)證的不是代碼本身,而是這些代碼所依賴的環(huán)境。

    [TestCase之間應(yīng)該盡量獨(dú)立]
    保證單獨(dú)運(yùn)行一個(gè)TestCase是有意義的。

    [不僅測(cè)試必須要通過(guò)的代碼,還要測(cè)試必須不能通過(guò)的代碼]
    這是一個(gè)小技巧,也是不同于設(shè)計(jì)思路的東西。像越界的值或者亂 碼,或者類型不符的變量,這些輸入都可能會(huì)導(dǎo)致某個(gè)異常的拋出,或者導(dǎo)致一個(gè)標(biāo)示“illegal parameters”的返回值,這兩種情況你都應(yīng)該測(cè)試。當(dāng)然我們無(wú)法枚舉所有錯(cuò)誤的輸入或外部環(huán)境,這就像我們無(wú)法枚舉所有正確的輸入和外部環(huán)境一 樣,只要TestCase能說(shuō)明問(wèn)題就可以了。

    [編寫代碼的第一步,是在TestCase中用Ctrl-C]
    這是一個(gè)高級(jí)技巧,呃,是的,我是這個(gè)意思,我不是說(shuō)這個(gè)技巧 難以掌握,而是說(shuō)這個(gè)技巧當(dāng)且僅當(dāng)你已經(jīng)是一個(gè)TDD高手時(shí),你才能體會(huì)到它的魅力。多次使用TDD的人都有這樣的體會(huì),既然我的TestCase已經(jīng)寫 的很好了,很能說(shuō)明問(wèn)題,為什么我的代碼不能從TestCase拷貝一些東西來(lái)呢。當(dāng)然,這要求你的TestCase已經(jīng)具有很好的表達(dá)能力,比如斷言f (5)=125的方式顯然沒(méi)有斷言f(5)=5^(5-2)表達(dá)更多的內(nèi)容。

    [測(cè)試用例包應(yīng)該盡量設(shè)計(jì)成可以自動(dòng)運(yùn)行的]
    如果產(chǎn)品是需要交付源代碼的,那我們應(yīng)該允許用戶對(duì)代碼進(jìn)行修改或擴(kuò)充后在自己 的環(huán)境下run整個(gè)測(cè)試用例包。既然通常情況下的產(chǎn)品是可以自動(dòng)運(yùn)行的,那為什么同樣作為交付用戶的制品,測(cè)試用例包就不是自動(dòng)運(yùn)行的呢?即使產(chǎn)品不需要 交付源代碼,測(cè)試用例包也應(yīng)該設(shè)計(jì)成可以自動(dòng)運(yùn)行的,這為測(cè)試部門或下一版本的開(kāi)發(fā)人員提供了極大的便利。

    [只亮一盞紅燈]
    大師的建議,前面已經(jīng)提到了,僅僅是建議。

    [用TestCase描述你發(fā)現(xiàn)的bug]
    如果你在另一個(gè)部門的同事使用了你的代碼,并且,他發(fā)現(xiàn)了一個(gè)bug,你猜他會(huì)怎 么做?他會(huì)立即走到你的工位邊上,大聲斥責(zé)說(shuō):“你有bug!”嗎?如果他膽敢這樣對(duì)你,對(duì)不起,你一定要冷靜下來(lái),不要當(dāng)面回罵他,相反你可以微微一 笑,然后心平氣和的對(duì)他說(shuō):“哦,是嗎?那么好吧,給我一個(gè)TestCase證明一下。”現(xiàn)在局勢(shì)已經(jīng)倒向你這一邊了,如果他還沒(méi)有準(zhǔn)備好回答你這致命的 一擊,我猜他會(huì)感到非常羞愧,并在內(nèi)心責(zé)怪自己太莽撞。事實(shí)上,如果他的TestCase沒(méi)有過(guò)多的要求你的代碼(而是按你們事前的契約),并且亮了紅 燈,那么就可以確定是你的bug,反之,對(duì)方則無(wú)理了。用TestCase描述bug的另一個(gè)好處是,不會(huì)因?yàn)橐院蟮男薷亩俅伪┞哆@個(gè)bug,它已經(jīng)成 為你發(fā)布每一個(gè)版本之前所必須檢查的內(nèi)容了。

    {關(guān)于單元測(cè)試}

    單元測(cè)試的目標(biāo)是

    Keep the bar green to keep the code clean

    這句話的含義是,事實(shí)上我們只做兩件事情:讓代碼奏效(Keep the bar green)和讓代碼潔凈(Keep the code clean),前者是把事情做對(duì),后者是把事情做好,兩者既是TDD中的兩頂帽子,又是xUnit架構(gòu)中的因果關(guān)系。

    單元測(cè)試作為軟件測(cè)試的一個(gè)類別,并非是xUnit架構(gòu)創(chuàng)造的,而是很早就有了。但是xUnit架構(gòu)使得單元測(cè)試變得直接、簡(jiǎn)單、高效和規(guī)范,這也 是單元測(cè)試最近幾年飛速發(fā)展成為衡量一個(gè)開(kāi)發(fā)工具和環(huán)境的主要指標(biāo)之一的原因。正如Martin Fowler所說(shuō):“軟件工程有史以來(lái)從沒(méi)有如此眾多的人大大收益于如此簡(jiǎn)單的代碼!”而且多數(shù)語(yǔ)言和平臺(tái)的xUnit架構(gòu)都是大同小異,有的僅是語(yǔ)言不 同,其中最有代表性的是JUnit和NUnit,后者是前者的創(chuàng)新和擴(kuò)展。一個(gè)單元測(cè)試框架xUnit應(yīng)該:1)使每個(gè)TestCase獨(dú)立運(yùn)行;2)使 每個(gè)TestCase可以獨(dú)立檢測(cè)和報(bào)告錯(cuò)誤;3)易于在每次運(yùn)行之前選擇TestCase。下面是我枚舉出的xUnit框架的概念,這些概念構(gòu)成了當(dāng)前 業(yè)界單元測(cè)試?yán)碚摵凸ぞ叩暮诵模?/p>

    [測(cè)試方法/TestMethod]
    測(cè)試的最小單位,直接表示為代碼。

    [測(cè)試用例/TestCase]
    由多個(gè)測(cè)試方法組成,是一個(gè)完整的對(duì)象,是很多TestRunner執(zhí)行的最小單位。

    [測(cè)試容器/TestSuite]
    由多個(gè)測(cè)試用例構(gòu)成,意在把相同含義的測(cè)試用例手動(dòng)安排在一起,TestSuite可以呈樹狀結(jié)構(gòu)因而便于管理。在實(shí)現(xiàn)時(shí),TestSuite形式上往往也是一個(gè)TestCase或TestFixture。

    [斷言/Assertion]
    斷言一般有三類,分別是比較斷言(如assertEquals),條件斷言(如isTrue),和斷言工具(如fail)。

    [測(cè)試設(shè)備/TestFixture]
    為每個(gè)測(cè)試用例安排一個(gè)SetUp方法和一個(gè)TearDown方法,前者用于在執(zhí)行該測(cè)試用例或該用例中的每個(gè)測(cè)試方法前調(diào)用以初始化某些內(nèi)容,后者在執(zhí)行該測(cè)試用例或該用例中的每個(gè)方法之后調(diào)用,通常用來(lái)消除測(cè)試對(duì)系統(tǒng)所做的修改。

    [期望異常/Expected Exception]
    期望該測(cè)試方法拋出某種指定的異常,作為一個(gè)“斷言”內(nèi)容,同時(shí)也防止因?yàn)楹锨楹侠淼漠惓6馔獾慕K止了測(cè)試過(guò)程。

    [種類/Category]
    為測(cè)試用例分類,實(shí)際使用時(shí)一般有TestSuite就不再使用Category,有Category就不再使用TestSuite。

    [忽略/Ignored]
    設(shè)定該測(cè)試用例或測(cè)試方法被忽略,也就是不執(zhí)行的意思。有些被拋棄的TestCase不愿刪除,可以定為Ignored。

    [測(cè)試執(zhí)行器/TestRunner]
    執(zhí)行測(cè)試的工具,表示以何種方式執(zhí)行測(cè)試,別誤會(huì),這可不是在代碼中規(guī)定的,完全是與測(cè)試內(nèi)容無(wú)關(guān)的行為。比如文本方式,AWT方式,swing方式,或者Eclipse的一個(gè)視圖等等。

    {實(shí)例:Fibonacci數(shù)列}

    下面的Sample展示TDDer是如何編寫一個(gè)旨在產(chǎn)生Fibonacci數(shù)列的方法。
    (1)首先寫一個(gè)TC,斷言fib(1) = 1;fib(2) = 1;這表示該數(shù)列的第一個(gè)元素和第二個(gè)元素都是1。

    public void testFab() {
            assertEquals(
    1, fib(1));
            assertEquals(
    1, fib(2));
    }

    (2)上面這段代碼不能編譯通過(guò),Great!——是的,我是說(shuō)Great!當(dāng)然,如果你正在用的是Eclipse那你不需要編譯,Eclipse 會(huì)告訴你不存在fib方法,單擊mark會(huì)問(wèn)你要不要新建一個(gè)fib方法,Oh,當(dāng)然!為了讓上面那個(gè)TC能通過(guò),我們這樣寫:

    public int fib( int n ) {
            
    return 1;
    }

    (3)現(xiàn)在那個(gè)TC亮了綠燈,wow!應(yīng)該慶祝一下了。接下來(lái)要增加TC的難度了,測(cè)第三個(gè)元素。

    public void testFab() {
            assertEquals(
    1, fib(1));
            assertEquals(
    1, fib(2));
            assertEquals(
    2, fib(3));
    }

    不過(guò)這樣寫還不太好看,不如這樣寫:

    public void testFab() {
            assertEquals(
    1, fib(1));
            assertEquals(
    1, fib(2));
            assertEquals(fib(
    1)+fib(2), fib(3));
    }

    (4)新增加的斷言導(dǎo)致了紅燈,為了扭轉(zhuǎn)這一局勢(shì)我們這樣修改fib方法,其中部分代碼是從上面的代碼中Ctrl-C/Ctrl-V來(lái)的:

    public int fib( int n ) {
            
    if ( n == 3 ) return fib(1)+fib(2);
            
    return 1;
    }

    (5)天哪,這真是個(gè)賤人寫的代碼!是啊,不是嗎?因?yàn)門C就是產(chǎn)品的藍(lán)本,產(chǎn)品只要恰好滿足TC就ok。所以事情發(fā)展到這個(gè)地步不是fib方法的錯(cuò),而是TC的錯(cuò),于是TC還要進(jìn)一步要求:

    public void testFab() {
            assertEquals(
    1, fib(1));
            assertEquals(
    1, fib(2));
            assertEquals(fib(
    1)+fib(2), fib(3));
            assertEquals(fib(
    2)+fib(3), fib(4));
    }

    (6)上有政策下有對(duì)策。

    public int fib( int n ) {
            
    if ( n == 3 ) return fib(1)+fib(2);
            
    if ( n == 4 ) return fib(2)+fib(3);
            
    return 1;
    }

    (7)好了,不玩了。現(xiàn)在已經(jīng)不是賤不賤的問(wèn)題了,現(xiàn)在的問(wèn)題是代碼出現(xiàn)了冗余,所以我們要做的是——重構(gòu):

    public int fib( int n ) {
            
    if ( n == 1 || n == 2 ) return 1;
            
    else return fib( n - 1 ) + fib( n - 2 );
    }

    (8)好,現(xiàn)在你已經(jīng)fib方法已經(jīng)寫完了嗎?錯(cuò)了,一個(gè)危險(xiǎn)的錯(cuò)誤,你忘了錯(cuò)誤的輸入了。我們令0表示Fibonacci中沒(méi)有這一項(xiàng)。

    public void testFab() {
            assertEquals(
    1, fib(1));
            assertEquals(
    1, fib(2));
            assertEquals(fib(
    1)+fib(2), fib(3));
            assertEquals(fib(
    2)+fib(3), fib(4));
            assertEquals(
    0, fib(0));
            assertEquals(
    0, fib(-1));
    }

    then change the method fib to make the bar grean:

    public int fib( int n ) {
            
    if ( n <= 0 ) return 0;
            
    if ( n == 1 || n == 2 ) return 1;
            
    else return fib( n - 1 ) + fib( n - 2 );
    }

    (9)下班前最后一件事情,把TC也重構(gòu)一下:

    public void testFab() {
            
    int cases[][] = {
                    {
    00}, {-10},  //the wrong parameters
                    {11}, {21}};  //the first 2 elements

            
    for (int i = 0; i < cases.length; i++)
                    assertEquals( cases[i][
    1], fib(cases[i][0]) );

            
    //the rest elements
            for (int i = 3; i < 20; i++)
                    assertEquals(fib(i
    -1)+fib(i-2), fib(i));
    }

    (10)打完收工。

    {關(guān)于本文的寫作}

    在本文的寫作過(guò)程中,作者也用到了TDD的思維,事實(shí)上作者先構(gòu)思要寫一篇什么樣的文章,然后寫出這篇文章應(yīng)該滿足的幾個(gè)要求,包括功能的要求(要 寫些什么)和性能的要求(可讀性如何)和質(zhì)量的要求(文字的要求),這些要求起初是一個(gè)也達(dá)不到的(因?yàn)檎倪€一個(gè)字沒(méi)有),在這種情況下作者的文章無(wú)法 編譯通過(guò),為了達(dá)到這些要求,作者不停的寫啊寫啊,終于在花盡了兩個(gè)月的心血之后完成了當(dāng)初既定的所有要求(make the bar green),隨后作者整理了一下文章的結(jié)構(gòu)(重構(gòu)),在滿意的提交給了Blog系統(tǒng)之后,作者穿上了一件綠色的汗衫,趴在地上,學(xué)了兩聲青蛙 叫。。。。。。。^_^

    {后記:Martin Fowler在中國(guó)}

    從本文正式完成到發(fā)表的幾個(gè)小時(shí)里,我偶然讀到了Martin Fowler先生北京訪談錄,其間提到了很多對(duì)測(cè)試驅(qū)動(dòng)開(kāi)發(fā)的看法,摘抄在此:

    Martin Fowler:當(dāng)然(值得花一半的時(shí)間來(lái)寫單元測(cè)試)!因?yàn)閱卧獪y(cè)試能夠使你更快的完成工作。無(wú)數(shù)次的實(shí)踐已經(jīng)證明這一點(diǎn)。你的時(shí)間越是緊張,就越要寫單元測(cè)試,它看上去慢,但實(shí)際上能夠幫助你更快、更舒服地達(dá)到目的。
    Martin Fowler:什么叫重要?什么叫不重要?這是需要逐漸認(rèn)識(shí)的,不是想當(dāng)然的。我為絕大多數(shù)的模塊寫單元測(cè)試,是有點(diǎn)煩人,但是當(dāng)你意識(shí)到這工作的價(jià)值時(shí),你會(huì)欣然的。
    Martin Fowler:對(duì)全世界的程序員我都是那么幾條建議:……第二,學(xué)習(xí)測(cè)試驅(qū)動(dòng)開(kāi)發(fā),這種新的方法會(huì)改變你對(duì)于軟件開(kāi)發(fā)的看法。……

    ——《程序員》,2005年7月刊

    {鳴謝}

    fhawk
    Dennis Chen
    般若菩提
    Kent Beck
    Martin Fowler
    c2.com

    (轉(zhuǎn)載本文需注明出處:Brian Sun @ 爬樹的泡泡[http://m.tkk7.com/briansun])

     

    posted on 2005-07-31 02:08 Brian Sun 閱讀(15323) 評(píng)論(26)  編輯  收藏 所屬分類: 軟件

    FeedBack:
    # re: 測(cè)試驅(qū)動(dòng)開(kāi)發(fā)全功略
    2005-08-01 15:28 | Brian Sun
    熱烈祝賀行業(yè)著名網(wǎng)絡(luò)雜志<<非程序員>>收錄本文。:)

    非程序員地址:http://www.umlchina.com
      回復(fù)  更多評(píng)論
      
    # re: 測(cè)試驅(qū)動(dòng)開(kāi)發(fā)全功略
    2005-08-01 15:31 | 般若菩提
    為什么如此真知灼見(jiàn)的文章沒(méi)人評(píng)價(jià),是不是文章太長(zhǎng),我滾了N屏才看完  回復(fù)  更多評(píng)論
      
    # re: 測(cè)試驅(qū)動(dòng)開(kāi)發(fā)全功略
    2005-08-01 17:33 | dudu
    祝賀!
    精品之作, 評(píng)價(jià)也顯得多余了。  回復(fù)  更多評(píng)論
      
    # re: 測(cè)試驅(qū)動(dòng)開(kāi)發(fā)全功略
    2005-08-01 22:16 | adou
    zzang!收藏了  回復(fù)  更多評(píng)論
      
    # re: 測(cè)試驅(qū)動(dòng)開(kāi)發(fā)全功略
    2005-08-02 09:40 | Frank Hawker
    好小子,寫得不錯(cuò),恭喜恭喜!  回復(fù)  更多評(píng)論
      
    # re: 測(cè)試驅(qū)動(dòng)開(kāi)發(fā)全功略
    2005-08-02 14:09 | Brian Sun
    謝謝謝謝。  回復(fù)  更多評(píng)論
      
    # re: 測(cè)試驅(qū)動(dòng)開(kāi)發(fā)全功略
    2005-08-06 07:51 | Brian Sun
    補(bǔ)充一個(gè)Best Practise:

    [每天留下一盞紅燈]
    按照大師的說(shuō)法,不必每天都做到全部綠燈的時(shí)候下班,相反,可以在每日離開(kāi)公司之前,寫一個(gè)不能通過(guò)的測(cè)試用例,這樣的好處是,第二天來(lái)工作的時(shí)候可以更容易的入手,因?yàn)樽蛱炝粝铝艘粋€(gè)不能通過(guò)的測(cè)試用例,那么我們就從這盞紅燈開(kāi)始吧。想想看,這對(duì)于很多時(shí)候——尤其是周一的早晨——都要畫很多時(shí)間來(lái)思考上一個(gè)工作日做到哪兒了的人來(lái)說(shuō)是個(gè)多么好的建議啊。  回復(fù)  更多評(píng)論
      
    # re: 測(cè)試驅(qū)動(dòng)開(kāi)發(fā)全功略
    2005-08-08 08:16 | 乖狗狗
    似乎有些MSF的精神在里面  回復(fù)  更多評(píng)論
      
    # re: 測(cè)試驅(qū)動(dòng)開(kāi)發(fā)全功略
    2005-09-01 13:39 | 閃來(lái)閃去的饅頭
    我先收藏了,有時(shí)間再慢慢看。  回復(fù)  更多評(píng)論
      
    # re: 測(cè)試驅(qū)動(dòng)開(kāi)發(fā)全功略
    2005-09-28 16:17 | freecat
    有問(wèn)題誠(chéng)心討教!
    我在開(kāi)發(fā)的過(guò)程中也要求做單元測(cè)試
    但我的代碼都是底層的,嵌入式方面
    很多移植來(lái)的代碼和函數(shù)并沒(méi)有輸入,甚至都沒(méi)有輸出
    而且很多時(shí)候都是對(duì)操作系統(tǒng)的函數(shù)進(jìn)行調(diào)用,或者直接改變寄存器之類的
    還有一些雖然有輸入但是是復(fù)雜的結(jié)構(gòu)作為參數(shù),內(nèi)容可能很復(fù)雜而且不確定
    請(qǐng)問(wèn)這種情況下如何做測(cè)試用例的編寫?

    我的email:wzq0325@163.com
    希望得到您的解答,謝謝!  回復(fù)  更多評(píng)論
      
    # re: 測(cè)試驅(qū)動(dòng)開(kāi)發(fā)全功略
    2005-11-16 16:06 | Brian Sun
    首先您做任何代碼都應(yīng)該有個(gè)期望的結(jié)果,如果結(jié)果是隨機(jī)的(這種情況很少),那么測(cè)試用例就是判別結(jié)果是否隨機(jī)即可;如果結(jié)果是確定的,也就是說(shuō)有對(duì)錯(cuò)之分,那么測(cè)試用例就判斷結(jié)果的對(duì)錯(cuò),這是個(gè)非常簡(jiǎn)單的原則,但是可以作為TDD的第一原則。

    至于您問(wèn)的有些專業(yè)的問(wèn)題,我認(rèn)為是測(cè)試用例以何種技術(shù)編寫和執(zhí)行的問(wèn)題,我沒(méi)怎么接觸過(guò)底層的代碼,所以真的不知道該給您怎樣的建議。至于復(fù)雜的數(shù)據(jù)結(jié)構(gòu),但愿它們可以獲得重用,如果不能重用,那也值得寫一個(gè)模擬真實(shí)的數(shù)據(jù)結(jié)構(gòu)去測(cè)試,否則復(fù)雜永遠(yuǎn)是復(fù)雜的,而測(cè)試遲早要人去做。

    例子是Eclipse,它是一個(gè)IDE,因此它要測(cè)試一個(gè)復(fù)雜的軟件項(xiàng)目能否很正確的編譯,它就寫了一個(gè)生成項(xiàng)目?jī)?nèi)容的程序來(lái)測(cè),并且覺(jué)得非常值得。

    我訂閱的RSS不知為何過(guò)濾了您的評(píng)論,非常抱歉沒(méi)能及時(shí)回復(fù),希望您能原諒,并繼續(xù)支持爬樹的泡泡,呵呵。

    泡泡
      回復(fù)  更多評(píng)論
      
    # re: 測(cè)試驅(qū)動(dòng)開(kāi)發(fā)全功略
    2005-11-23 17:28 | coolyu
    贊一個(gè),從非程序員找到這個(gè)blog,粉不錯(cuò)。
    雖然我沒(méi)有實(shí)踐過(guò)TDD,但是這個(gè)也從另一個(gè)方面證明測(cè)試是灰常重要的(呵呵,一副國(guó)家領(lǐng)導(dǎo)人在某某重要會(huì)議上的口氣)。但我們的現(xiàn)實(shí)project中,經(jīng)常因?yàn)殚_(kāi)發(fā)人員的單元測(cè)試、測(cè)試人員的集成測(cè)試等沒(méi)有到位而引發(fā)很多問(wèn)題。
    支持lz繼續(xù)文章不斷^_^  回復(fù)  更多評(píng)論
      
    # re: 測(cè)試驅(qū)動(dòng)開(kāi)發(fā)全功略
    2005-11-24 09:56 | Brian Sun
    說(shuō)的是啊,所以我們要致力于改善國(guó)內(nèi)軟件界的這個(gè)狀況。:)
      回復(fù)  更多評(píng)論
      
    # re: 測(cè)試驅(qū)動(dòng)開(kāi)發(fā)全功略
    2006-04-10 16:42 | haha
    特別好!^_^  回復(fù)  更多評(píng)論
      
    # re: 測(cè)試驅(qū)動(dòng)開(kāi)發(fā)全功略
    2006-04-18 16:14 | sw.pollux
    好文章,如果能補(bǔ)充unit test的優(yōu)點(diǎn)那就更完美了 :)
    我現(xiàn)在也在想寫一篇關(guān)于tdd的文章,希望到時(shí)有機(jī)會(huì)一起討論!  回復(fù)  更多評(píng)論
      
    # re: 測(cè)試驅(qū)動(dòng)開(kāi)發(fā)全功略
    2006-05-02 12:00 | 乖狗狗
    了解了一些IPD-CMM和敏捷軟件開(kāi)發(fā),包括極限編程的知識(shí)之后
    重讀泡泡的這篇文章
    發(fā)現(xiàn)了一些新的問(wèn)題
    對(duì)于很多算法來(lái)說(shuō),測(cè)試的方法和實(shí)現(xiàn)的方法很可能完全不同,請(qǐng)問(wèn)泡泡此時(shí)該怎么辦?
    比如一個(gè) 精確求解算術(shù)平方根的算法(假設(shè)我們?cè)趯?shí)現(xiàn)時(shí)不使用到sqrt()函數(shù)只用基本的四則運(yùn)算操作的話)
    這時(shí)候好像TDD就起不了什么作用了  回復(fù)  更多評(píng)論
      
    # re: 測(cè)試驅(qū)動(dòng)開(kāi)發(fā)全功略
    # re: 測(cè)試驅(qū)動(dòng)開(kāi)發(fā)全功略
    2006-09-28 16:18 | 敏捷團(tuán)隊(duì)
    樓主,和我年紀(jì)相似,我也是83年春天,樓主的兩個(gè)胖子說(shuō)的是什么地方?  回復(fù)  更多評(píng)論
      
    # re: 測(cè)試驅(qū)動(dòng)開(kāi)發(fā)全功略
    2007-01-21 14:37 | ncs
    合肥吧  回復(fù)  更多評(píng)論
      
    # re: 測(cè)試驅(qū)動(dòng)開(kāi)發(fā)全功略
    2007-05-29 13:39 | 金天風(fēng)
    呵呵,我也愛(ài)這么做事。。現(xiàn)在終于找到理論基礎(chǔ)了,,謝謝啊!  回復(fù)  更多評(píng)論
      
    # re: 測(cè)試驅(qū)動(dòng)開(kāi)發(fā)全功略
    2008-06-23 19:10 | AaronHu
    剛剛接觸agile和tdd,看了很多資料,但是感覺(jué)效果不好,
    看了樓主的博客,有種茅塞頓開(kāi)之感,多謝。  回復(fù)  更多評(píng)論
      
    # re: 測(cè)試驅(qū)動(dòng)開(kāi)發(fā)全功略
    2009-02-11 13:02 | 過(guò)路的人
    真的還不錯(cuò)哈  回復(fù)  更多評(píng)論
      
    # re: 測(cè)試驅(qū)動(dòng)開(kāi)發(fā)全功略
    2010-09-13 15:47 | 不得不回
    不得不說(shuō),這文章是精品,我剛開(kāi)始接觸TDD,還無(wú)法把這種開(kāi)發(fā)方法應(yīng)用到日常開(kāi)發(fā)中,但如果我學(xué)會(huì)了,我編程水平會(huì)有很大的進(jìn)步,我相信  回復(fù)  更多評(píng)論
      
    # re: 測(cè)試驅(qū)動(dòng)開(kāi)發(fā)全功略
    2012-01-30 15:43 | larry cai
    寫得相當(dāng)不錯(cuò)。  回復(fù)  更多評(píng)論
      
    # re: 測(cè)試驅(qū)動(dòng)開(kāi)發(fā)全功略[未登錄](méi)
    2014-06-18 16:55 | 卓越
    內(nèi)容不錯(cuò),我是剛解除測(cè)試驅(qū)動(dòng)開(kāi)發(fā)的,看完后至少讓我明白大體的思想,以及要如何運(yùn)用到我的工作中,比較實(shí)踐性的一篇文章,找了一下午文檔,總算有點(diǎn)收獲了,謝謝。  回復(fù)  更多評(píng)論
      
    # re: 測(cè)試驅(qū)動(dòng)開(kāi)發(fā)全功略
    2016-03-28 16:20 | agario
    Just wanted to say that I read your blog quite frequently and I’m always amazed at some of the stuff people post here. But keep up the good work, it’s always interesting. See ya,
    http://super-mechs.com
      回復(fù)  更多評(píng)論
      
    主站蜘蛛池模板: 小小影视日本动漫观看免费 | 成人免费无码H在线观看不卡| 精品国产污污免费网站| 国产无人区码卡二卡三卡免费| 又粗又大又硬又爽的免费视频| 久久精品亚洲精品国产色婷| 免费福利资源站在线视频| 7m凹凸精品分类大全免费| 免费一级成人毛片| 久久久久精品国产亚洲AV无码| 国产三级在线免费观看| 最近中文字幕无免费视频| 国产亚洲精品精华液| 亚洲国产成人AV网站| 亚洲高清中文字幕免费| 久久被窝电影亚洲爽爽爽| 99亚洲男女激情在线观看| 国产免费一区二区三区| 亚洲色欲久久久综合网 | 亚洲日本天堂在线| 久草免费福利资源站| 亚洲AV无码不卡在线观看下载 | 亚洲爆乳精品无码一区二区| 久久精品视频免费看| 亚洲成a人片在线观看国产| 亚洲Av高清一区二区三区| 永久免费A∨片在线观看| 免费a级毛片网站| 亚洲国产乱码最新视频| 一级毛片不卡片免费观看| 亚洲精品偷拍视频免费观看| 亚洲乱码中文字幕在线| 最近2019中文字幕免费直播| 亚洲色欲一区二区三区在线观看| 亚洲a无码综合a国产av中文| 91免费精品国自产拍在线不卡| 婷婷亚洲久悠悠色悠在线播放 | 成年午夜视频免费观看视频| 精品日韩亚洲AV无码一区二区三区| www一区二区www免费| 免费国产成人午夜私人影视|