天天看點

<測試驅動開發實用指南>讀書筆記

[align=center][img]http://images.china-pub.com/ebook15001-20000/19120/shupi.jpg[/img][/align]

裡面的一些測試技術都很老了, 比如junit, 現在都注解了.

本來是想跟着裡面的電影清單的例子來實踐一把的, 不過對swing不熟悉, 而且沒有源代碼可以下載下傳的, 遇到了一些書面上沒有提到的代碼, 導緻中間沒法繼續下去.

前面幾章的一些理論還是不錯的, 有些以前自己已經知道了, 現在再看一遍, 有一種頓悟的感覺.

如果能拿java最擅長的web應用做例子就完美了, 畢竟做swing應用的人比較少, 至少在國内是如此.

[b]寫測試的步驟[/b]

1.開始先編寫一個測試, 在測試開頭增加一條想讓它為true的斷言

2.然後為使斷言為true創造條件

3.最後需要為建立我們所需要的實際代碼.

4.在測試通過之後, 開始消除為使測試通過而引入的重複以及其他的一些壞味道代碼.

[b]關于重複的一個例子[/b]

比如要計算5和3的平均值, 我們可以在真實代碼中直接傳回4, 當這個結果通過計算得出結果卻傳回一個常量時, 這就是一種形式的重複.

要去掉重複, 首先這樣做:

public int getAverage(){return (3+5)/2;}
           

不過這裡仍然存在重複: 3, 5與提供給參數是重複的, 是以需要通過一個參數用來儲存累加的結果:

private int total;
public void add(int i){total +=i;}
public int getAverage(){return total/2;}
           

這裡因為重構的時候而引入了一個常量2, 這也是一種重複, 需要通過記錄每次累加測試來去掉:

private int number;
public void add(int i){total +=i; number ++;}
public int getAverage(){return total/number;}
           

為了對我們的修改增加一些自信, 我們可以增加一些新的測試.

在每次小的改動之後運作測試可以給我們信心和保證, 其結果有了下一步工作的勇氣, 每次一小步一小步地推進, 勸告那些完美主義者不要一步到位, 循序漸進, 不要妄想一口吃成胖子.

在消除重複的過程中, 我們還有另外一種思路, 就是通過再編寫一個測試, 然後通過重構保證兩個測試通過.

但是無論采用哪種思路, 都需要編寫另外一個測試, 這樣既可以驅動歸納工作的進行, 也可以進一步驗證

[b]重構[/b]

重構與TDD兩個密切相關的兩個方面:

盡可能采用簡單的方法來讓測試獲得通過, 然後通過重構來對代碼進行整理, 其中大部分工作是消除那些為使測試通過引入的重複

當采用TDD之後, 那麼就有了放手重構的安全網.

[b]重構的時機[/b]:

當存在重複的時候

當覺得代碼或者代碼所表達的意圖不夠清晰的時候

當覺察到代碼可能存在壞味道或者有壞味道的傾向的時候

在你要讓某個測試通過的時候, 帶上編碼的帽子, 一旦測試通過, 你就換頂帽子執行重構來進行清理.

[b]關于意圖[/b]

當我們在編寫測試代碼的時候, 我們會強迫自己考慮類的接口而不是其實作, 我們就有機會站在使用這個類的使用者的立場來判定什麼才是最有意義的, 而不是陷入具體的實作細節中去.

[b]code smell[/b]

[b]注釋[/b]:如果你看到一條注釋或者覺得有必要編寫一條注釋的話, 那麼請首先要考慮重構或重寫代碼.

[b]資料類[/b]:對某個類資料成員的操作處理應該移到該類的内部, 而不是将其遺棄在該類之外, 讓其他的類對其"蹂躏"修改, 這個也展現了封裝的原則. "上帝的歸上帝, 凱撒的歸凱撒"

[b]交往不當[/b]:這種情況是指一個類對另一個類的内部細節知道太多.要處理這種情況, 需要對方法進行遷移, 讓那些彼此了解的代碼處于同一位置. 這樣一旦這些内部細節發生變化的時候, 其影響的範圍會僅在該類的内部, 而不會出現擴散.

對于繼承也會有類似的問題, 子類過多的了解祖先類的實作細節, 超出它所了解的, 這樣就應該把繼承改成委派(delegation), 或者将這種關系松散化, 達到去耦的目的.

[b]類尺寸過大[/b]:應該采用抽取出子類或者采用多态來減小之

[b]方法過長[/b]:一般情況下是完成的工作太多了.

[b]重構手段[/b](手法千千萬, 常用就這幾種)

[b]extract class[/b]:當一個類變的太大或者行為邏輯組織分散時, 另一種抽取的原因是由于我們需要某種行為的多種實作.

比如電影清單類有一個功能需要輸出一個電影清單, 那麼我們可以将這個功能拆分到一個單獨的類中去, 這樣就能夠很容易的進行替換和改進.

[b]extract interface[/b]: 記住一點就好, 接口最好是小而專.關于接口的命名, 盡量采用通過添加-able, -ible結尾的形容詞, 但是有時候這種命名沒有 , 這可以使用添加字首I, 比如MovieListable沒有意義, 我們可以采用IMovieList.

[b]extract method[/b]: 通過給一塊完成某種功能的代碼加注釋或者通過空行來清晰代碼都是一種潛在的壞味道, 需要通過提取方法将代碼拆分到各自的方法中.

[b]replace type code withsubclasses[/b]: 當我們的類使用類型代碼來表示子類型的時候, 可以使用該手段來打破那些根據類型編碼進行判别的複雜條件判斷和switch語句.

[b]replace conditional with polymorphism[/b]: 當發現switch語句的愛好ihou可以考慮建立子類來處理各種不同的情況. 進而去掉switch.

[b]form template method[/b]: 我的最愛, 甚至達到濫用的程度:(

[b]introduce explaining variable[/b]:當我們的表達式複雜而且難以立即時, 我們可以提取其中的某些部分, 把中間結果儲存在命名清楚的臨時變量中.

[b]replace constructor with factory method[/b]:當存在多個用于建立類的不同類型的執行個體的構造方法時, 使用起來不是很容易區分, 則需要通過使用靜态工廠方法, 給每個構造方法起一個有意義的名字.

[b]replace inheritance with delegation[/b]: 當子類是特殊種類的超類, 或者子類對超類進行擴充而不是複寫超類的部分功能時, 才使用繼承.

設計模式應該是重構的目标, 應該通過重構逐漸引入設計模式.

如果發現了給參數指派的代碼, 那麼應該使用臨時變量取而代之.

在開始編碼的時候, 我們應該強迫自己采用最簡單的做法.

[b]注釋[/b]

注釋存在的目的是為了掩蓋代碼的臭味.

正當的注釋:

未完成的代碼(TODO)

重構尚無法足夠清晰

使用了某種非同尋常的算法

使用某種别人釋出的算法

性能調整

類注釋(解釋這個類為什麼存在以及用途, 要避免編寫有關這個類的使用教程)

[b]真正的TDD應該[/b]

測試方法應該盡量簡短而切中要害

編寫一點測試, 編寫一點代碼(test a little, code a little)

不要一口氣把所有的測試都寫完, 然後再編寫代碼, 而要編寫一個測試, 讓其通過, 在編寫一個測試, 再讓其運作通過, 以此類推.

萬事開頭難, 應該從編寫最簡單的測試開始.

[b]測試模式[/b]

設定前置條件

執行相應的功能

檢查後置條件是否滿足

[b]TestCase[/b]

應該将TestCase視為一種需要需要以完全相同的設定方式來組織測試的方法, 而不是用它來組織給定類的測試.

每當你發現setUp中的有些代碼使用某些測試方法, 而有些代碼不使用其他測試方法時, 那麼就應該認為這個TestCase應該被重構為兩個或者多個TestCase.

[b]

何謂簡單的測試對象[/b]:

正确的處理null值

空集或null對象的行為

遞歸或疊代結構以及遞歸或疊代計算的基本情況(沒明白)

應該盡量使用assertEquals()

盡量在assert中給出相關的message, 沒有message也是一種bad smell, 偶沒這個習慣:(

盡量保持測試方法中的斷言最少, 這樣可以保證測試專一, 簡潔, 容易了解

編寫測試從assertXxx()開始.

測試代碼的數量與應用代碼一樣多, 要是能多上一半就更好了

力争每個測試方法中有隻出現一個斷言

測試做得好, 調試器用的少

TDD事前需要做大量的工作, 這個工作的收益主要展現在減少了後期調試程式的工作量

一旦你找到了TDD的感覺, 你就會比直接寫代碼和調試器來進行開發的工作速度快得多.

[b]XP[/b]

xp中的四種變化量:成本, 時間, 品質, 範圍

其中任何一個的價值依賴于其他三個的價值, 你最多隻能控制四個中的三個, 而絕對無法同時控制四個.

xp的價值觀:溝通, 簡單, 回報, 勇氣

溝通在xp中具有至高無上的重要性, 其外在表現形式:

結對程式設計

每天早上一次站立會議

在開放的環境工作

客戶與開發團隊一起工作

大量使用白闆

把都感興趣的資訊放在顯著的位置

[b]改進設計[/b]

在程式設計的時候, 你先編寫一個測試(剛剛能夠失敗就行), 然後編寫一小段代碼(剛剛能夠保證測試運作通過就行), 這一過程會産生設計或結構低劣的代碼, 是以下一步就是通過重構來使代碼重新恢複漸漸.

極限程式設計就是讓程式員們來編寫程式, 謀生, 并且從中獲得樂趣.

要想擁抱變化, 我們就需要采用一種漸進的開發方式, 每次隻改變系統的一小部分, 而不是在一次大的傳遞中搞定所有的一切.

[b]agile model[/b]

靈活模組化的兩個基本目的:為了解某一問題而模組化(諸如如何設計系統的某一部分);為了傳達團隊正在完成的工作而模組化.

靈活模型大部分都是臨時性的, 當這些模型完成他們的使命之後, 繼續留存已經沒有價值.

靈活模型是一種剛剛夠好(just good enough)的模型

繼續閱讀