測試驅(qū)動開發(fā) -TDD

測試驅(qū)動開發(fā)TDD-Test Driven Development是敏捷開發(fā)中的一種實(shí)踐開發(fā)模式,簡單來說即:測試代碼優(yōu)先于產(chǎn)品代碼編寫,通過測試不斷驅(qū)動編寫完善的產(chǎn)品代碼拂到,實(shí)現(xiàn)所需的功能帅刊。
測試驅(qū)動開發(fā)與通常開發(fā)模式在角度和思考方式上都有著本質(zhì)的區(qū)別走芋,并且剛接觸TDD會讓人難以接受全闷。
在通常模式下叉寂,在拿到一個(gè)需求后,經(jīng)過簡單的思考設(shè)計(jì)(通常是紙上畫符)就直接進(jìn)入功能實(shí)現(xiàn)的開發(fā)总珠。在開發(fā)完成后再編寫測試用例并運(yùn)行測試屏鳍,修復(fù)bug讓代碼能工作。而測試驅(qū)動開發(fā)則正好相反局服,在拿到需求后開始寫的第一個(gè)代碼時(shí)測試用例钓瞭。本質(zhì)上是通過測試用例來描述需求,并編寫產(chǎn)品代碼使得測試通過淫奔。

一山涡、 TDD原則

測試驅(qū)動開發(fā)所遵循的三個(gè)基本原則如下:

  1. 除非能讓失敗的單元測試通過,否則不允許去編寫任何的產(chǎn)品代碼唆迁。
    對于任何功能需求鸭丛,都是先從寫測試用例入手,為滿足測試用例才能去寫產(chǎn)品代碼媒惕。

  2. 只允許編寫剛好能夠?qū)е率〉膯卧獪y試系吩。 (編譯失敗也屬于一種失敗)
    通常在開發(fā)完成后寫的測試用例都是希望能通過的測試用例妒蔚,很可能因先入為主導(dǎo)致不能正確覆蓋測試。相反月弛,TDD編寫新的測試用例是為了覆蓋不同的需求肴盏,導(dǎo)致失敗。

  3. 只允許編寫剛好能夠使一個(gè)失敗的單元測試通過的產(chǎn)品代碼帽衙。
    編寫的生產(chǎn)代碼只能是為了使一個(gè)失敗的單元測試通過菜皂,不應(yīng)編寫多余的實(shí)現(xiàn)代碼。如果過多編寫了實(shí)現(xiàn)其他功能業(yè)務(wù)的代碼厉萝,則違反了TDD的原則恍飘。

測試驅(qū)動開發(fā)的基本流程

  • 編寫單元測試 --> 運(yùn)行單元測試-失敗
  • 編寫生產(chǎn)代碼 --> 運(yùn)行單元測試
  • 重構(gòu)代碼 -->運(yùn)行單元測試保證通過
    從流程還可以看出,測試驅(qū)動開發(fā)將持續(xù)的重構(gòu)納入流程之重谴垫,并通過測試保證了重構(gòu)的正確性章母。因?yàn)閱卧獪y試運(yùn)行失敗為紅色,通過為綠色翩剪,因此TDD流程也可以簡單描述為:
    紅乳怎、綠、重構(gòu)前弯。

二蚪缀、 TDD實(shí)踐

下面通過經(jīng)典的Bob大叔關(guān)于保齡球計(jì)分的例子來進(jìn)行說明秫逝,如何來實(shí)踐TDD。
首先簡單介紹下保齡球積分規(guī)則:

  • 每一局總共有十輪询枚,每輪一開始會有十支球瓶违帆,球手可以扔兩次球,目標(biāo)就是用盡量少的球把全部球瓶擊倒金蜀。
  • 如果第一球就把全部的球瓶都擊倒了前方,也就是STRIKE-全中,就算完成一輪了廉油,本輪分?jǐn)?shù)是10分再加獎(jiǎng)勵(lì)(bonus):即后面兩球的倒瓶數(shù)惠险,
  • 如果第一球沒有全倒,就要再打一球抒线,如果第二球?qū)⑹O碌那蚱咳紦舻拱喙簿褪荢PARE-補(bǔ)中,也算完成一輪嘶炭,本輪分?jǐn)?shù)為10分再加獎(jiǎng)勵(lì)(bonus)即:下一球的倒瓶數(shù)抱慌,
  • 如果第二球也沒有把球瓶全部擊倒的話,那分?jǐn)?shù)就是第一球加第二球倒的瓶數(shù)眨猎,沒有獎(jiǎng)勵(lì)(bonus)抑进,再接著打下一輪。依此類推睡陪。
  • 如果在第十輪出現(xiàn)STRIKE或者SPARE寺渗,則球手可再加打第三球,最多只能打三球。
  • 全部十輪的得分相加就等于這一局的總得分。

我們的需求是
提供一個(gè)Game類荧库,并且包含2個(gè)方法

  • roll(int pins):用于玩家每次扔球后擊倒的瓶子數(shù),參數(shù)即為擊倒的瓶子數(shù)
  • score():每局結(jié)束后調(diào)用計(jì)算這一局的總分?jǐn)?shù)涡拘。

根據(jù)TDD的原則,拿到需求后我們第一反應(yīng)不是去設(shè)計(jì)并實(shí)現(xiàn)上述規(guī)則据德,而是應(yīng)當(dāng)先編寫測試用例鳄乏。

1. 第一個(gè)測試用例

先編寫一個(gè)最簡單的測試用例,即每次投球都沒有擊倒瓶子棘利,很明顯最終得分應(yīng)該是0橱野。


image.png

很明顯因?yàn)镚ame類不存在,測試是不會通過的赡译,因此我們需要去創(chuàng)建Game類使測試通過(在這里不應(yīng)當(dāng)寫更多實(shí)現(xiàn)代碼)仲吏。


image.png

接下來,我們增加投球的代碼,假如每次都沒擊中裹唆,即倒瓶數(shù)都是0:因?yàn)閞oll方法不存在誓斥,因此需要我們在Game類中增加roll方法(此時(shí)不用關(guān)心具體的實(shí)現(xiàn))。


image.png

同樣的增加一局結(jié)束后算分方法(同樣不關(guān)心實(shí)現(xiàn))许帐,此時(shí)測試不通過劳坑。


image.png

需要修改產(chǎn)品代碼使測試通過,此時(shí)我們不考慮具體實(shí)現(xiàn)成畦,簡單返回一個(gè)0使測試通過距芬。


image.png

2. 第二個(gè)測試用例

第一個(gè)測試用例僅為每輪都沒擊倒瓶子的情況,下面我們編寫測試用例每次投球都只擊倒1個(gè)瓶子循帐。即沒有全中也沒有補(bǔ)中框仔,最終得分應(yīng)該是20。


image.png

編寫測試用例并運(yùn)行拄养,很顯然測試不會通過离斩,我們需要修改產(chǎn)品代碼。很明顯最簡單的實(shí)現(xiàn)是需要我們累加每次擊球后的分?jǐn)?shù)瘪匿。通過一個(gè)成員變量score記錄分值并累加跛梗,測試通過。


image.png

同時(shí)我們發(fā)現(xiàn)測試用例中的循環(huán)投球代碼出現(xiàn)了重復(fù)棋弥,我們可以進(jìn)行代碼的提取重構(gòu)核偿。我們將投球代碼提取為獨(dú)立的方法給測試用例調(diào)用。并再次運(yùn)行測試顽染,保證測試通過漾岳。


image.png

3. 第三個(gè)測試用例

現(xiàn)在我們來考慮下出現(xiàn)補(bǔ)中SPARE的情況,并編寫對應(yīng)的測試用例家乘。為了簡單蝗羊,我們先只考慮出現(xiàn)一次全中:第一輪投球?yàn)?,5仁锯;第三球?yàn)?,其他全是沒中-0翔悠。這樣一局得分應(yīng)該是:第一輪10分+(獎(jiǎng)勵(lì)-第三球得分+3)+第二輪得分3+其他得分0 =16业崖。運(yùn)行測試用例-失敗。


image.png

我們需要修改產(chǎn)品代碼滿足出現(xiàn)補(bǔ)中的情況蓄愁。這時(shí)我們發(fā)現(xiàn)代碼上有些問題:roll方法本來應(yīng)當(dāng)用來記錄每次擊倒的瓶子數(shù)双炕,實(shí)際卻用來計(jì)算分?jǐn)?shù),而score方法本來應(yīng)用來計(jì)算分?jǐn)?shù)撮抓,但卻沒有實(shí)現(xiàn)妇斤,代碼需要重構(gòu)。
這里我們回退一步,回到第二個(gè)測試用例通過的情況站超,并對代碼進(jìn)行重構(gòu)荸恕。
因?yàn)橐涗浢看螕舻沟钠孔訑?shù),所以我們引入一個(gè)整型數(shù)組死相,并通過一個(gè)索引來指示當(dāng)前是第幾球融求。在roll方法中對擊倒數(shù)進(jìn)行記錄。在score方法中根據(jù)擊倒數(shù)進(jìn)行分值計(jì)算算撮。通過測試用例保證我們的重構(gòu)是正確的生宛。


image.png

現(xiàn)在我們回到第三個(gè)測試用例,它依然是未通過狀態(tài)肮柜。因?yàn)檠a(bǔ)中為2球擊倒10球陷舅,因此在計(jì)算得分時(shí)需要按照2球一輪來進(jìn)行考慮,同時(shí)來處理補(bǔ)中的情況审洞。修改產(chǎn)品代碼使測試用例通過莱睁。


image.png

現(xiàn)在來會看我們的代碼,可以發(fā)現(xiàn)為了解釋代碼我們加了一些注釋(spare)预明,說明代碼不能自解釋缩赛。同時(shí)我們代碼中有隨意定義的變量i和很長的條件語句,我們對代碼先進(jìn)行一些重構(gòu)撰糠,提取方法酥馍,并修改變量名為有意義的名字。測試用例保證了我們的修改不會破壞當(dāng)前代碼阅酪。


image.png

進(jìn)入下一個(gè)紅旨袒、綠、重構(gòu)循環(huán)术辐,完成全中STRIKE的支持和代碼優(yōu)化砚尽。

三、 總結(jié)

上面就是一個(gè)TDD的實(shí)踐過程辉词,從中我們可以看出這樣幾點(diǎn):

  1. 單元測試保證了編碼過程中持續(xù)重構(gòu)的正確必孤。在完成代碼的編寫后,我們會得到很多的測試代碼瑞躺,而這些測試代碼可以用來保證對代碼后續(xù)的維護(hù)修改的正確性敷搪。單元測試對代碼的覆蓋率同樣可以增強(qiáng)我們對代碼的信心。
  2. 豐富的單元測試完全可以替代接口文檔幢哨,更能清楚的描述代碼實(shí)現(xiàn)的功能赡勘。
  3. TDD的開發(fā)模式促使了代碼的抽取和解耦,利于代碼復(fù)用捞镰。

TDD在現(xiàn)實(shí)中的情況

  1. 在實(shí)際情況中真正應(yīng)用TDD模式來進(jìn)行開發(fā)的公司和團(tuán)隊(duì)少之又少闸与,具體分析大概有以下原因:
  2. 公司或團(tuán)隊(duì)沒有推動支持毙替。部分公司和團(tuán)隊(duì)甚至不能很好的推行單元測試,TDD更無從談起践樱。另外雖然TDD能保證產(chǎn)出更高質(zhì)量的代碼厂画,但會被認(rèn)為可能需要耗費(fèi)更多時(shí)間。
  3. TDD模式跟通常的思維習(xí)慣相反映胁,讓開發(fā)人員很難接受木羹。
  4. 某些項(xiàng)目運(yùn)行單元測試耗時(shí)太長。即使有很多輔助工具的使用解孙,在一個(gè)復(fù)雜項(xiàng)目里運(yùn)行單元測試仍然不是一個(gè)隨手操作的事情坑填。

參考文檔:
Bobo大叔保齡球例子 可以下載講解PPT
簡書上一個(gè)更詳細(xì)的文章

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市弛姜,隨后出現(xiàn)的幾起案子脐瑰,更是在濱河造成了極大的恐慌,老刑警劉巖廷臼,帶你破解...
    沈念sama閱讀 217,185評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件苍在,死亡現(xiàn)場離奇詭異,居然都是意外死亡荠商,警方通過查閱死者的電腦和手機(jī)寂恬,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評論 3 393
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來莱没,“玉大人初肉,你說我怎么就攤上這事∈味悖” “怎么了牙咏?”我有些...
    開封第一講書人閱讀 163,524評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長嘹裂。 經(jīng)常有香客問我妄壶,道長,這世上最難降的妖魔是什么寄狼? 我笑而不...
    開封第一講書人閱讀 58,339評論 1 293
  • 正文 為了忘掉前任丁寄,我火速辦了婚禮,結(jié)果婚禮上泊愧,老公的妹妹穿的比我還像新娘狡逢。我一直安慰自己,他們只是感情好拼卵,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,387評論 6 391
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著蛮艰,像睡著了一般腋腮。 火紅的嫁衣襯著肌膚如雪雀彼。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,287評論 1 301
  • 那天即寡,我揣著相機(jī)與錄音徊哑,去河邊找鬼。 笑死聪富,一個(gè)胖子當(dāng)著我的面吹牛莺丑,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播墩蔓,決...
    沈念sama閱讀 40,130評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼梢莽,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了奸披?” 一聲冷哼從身側(cè)響起昏名,我...
    開封第一講書人閱讀 38,985評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎阵面,沒想到半個(gè)月后轻局,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,420評論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡样刷,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,617評論 3 334
  • 正文 我和宋清朗相戀三年仑扑,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片置鼻。...
    茶點(diǎn)故事閱讀 39,779評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡镇饮,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出沃疮,到底是詐尸還是另有隱情盒让,我是刑警寧澤,帶...
    沈念sama閱讀 35,477評論 5 345
  • 正文 年R本政府宣布司蔬,位于F島的核電站邑茄,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏俊啼。R本人自食惡果不足惜肺缕,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,088評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望授帕。 院中可真熱鬧同木,春花似錦、人聲如沸跛十。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽芥映。三九已至洲尊,卻和暖如春远豺,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背坞嘀。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評論 1 269
  • 我被黑心中介騙來泰國打工躯护, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人丽涩。 一個(gè)月前我還...
    沈念sama閱讀 47,876評論 2 370
  • 正文 我出身青樓棺滞,卻偏偏與公主長得像,于是被迫代替她去往敵國和親矢渊。 傳聞我的和親對象是個(gè)殘疾皇子继准,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,700評論 2 354

推薦閱讀更多精彩內(nèi)容