測試驅動開發的編寫周期
(簡單的總體把握)
應該知道,沒有測試,就沒有功能代碼。測試驅動開發這種程式設計方式怎麼開始呢,那就是先寫一個新的測試
梗概如下:
- 添加一個測試;
/** 要明白,現在這個測試裡所用到的類和方法都是不存在的。此時的測試甚至是編譯無法通過! */ @Test public void testMovieRating() { Movie starWars = new Movie("Star Wars"); starWars.addRating(3); starWars.addRating(5); assertEquals("Bad average rating", 4, starWars.getAverageRating()); }
- 運作所有的測試并檢視失敗的;
/** 通過運作所有的測試,我們将會收到錯誤的資訊提示,告訴了我們現在測試中存在的問題。可想見如下: 1.不存在Movie類 2.不存在addRating() 3.不存在getAverageRating() 如何解決?很簡單,按照提示,利用開發環境(編譯器如IDea)的強大功能迅速建立一個Movie類、方法。 */ public class Movie { public Movie(String name) {} public void addRating(int newRating) {} public int getAverageRating() { return 0;} }
可以看見上面示例,所有的類和方法都是一個外殼,僅僅提供了外部行為,内部的實作都是啞實作(有着傳回值的方法都應該初步傳回一個簡單的預設值!)。可想見,現在測試已經通過了編譯,再運作試試呢?失敗!提示我們:Bad average rating 期待的是4,實際的是0。 為了使測試能夠通過,我們要“不折手段”了!既然想要4,那麼我們這樣做:
public int getAverageRating() { return 4;}
現在,重新運作所有!測試呢:通過!!接下來要做的事情就是重構。
- 對測試進行微小的改動;(書中原話——測試驅動開發 Kent Beck)【為什麼不是對功能代碼進行微小修改,怎麼是對測試呢。。】
- 通過重構去掉重複部分。(重複部分是指測試中的資料與程式之中的資料之間的重複)
/** 上面的功能代碼僅僅能完成那個期待4的測試。要想程式更加通用,接下來我們要泛化程式。 目标就是:讓程式能夠計算後傳回電影評分的平均值。于是我們需要對程式裡的4這個常量做出思考: 要想泛化,就不能是常量(在這兒來看),是以要将它替換為一個變量。 4從何來?可以想見:Movie類裡有着添加評分的方法addRating(), 是以4=(3+5)/2,即 平均分=總評分/評分次數。于是: */ public class Movie { private int totalRating = 0; private int numberOfRatings = 0; public Movie(String name) {} public void addRating(int newRating) { totalRating += newRating; numberOfRatings++; /** 從上往下,我們已經做了很多修改,記住:本應該修改就要重新測試,不過明顯從前面到這兒的修改, 不會出錯,那麼就省去每添一句新的代碼就重新測試這樣繁雜、死闆的步驟吧。 不過現在我們已經設計到了一個方法的很多修改,我想是時候去運作一遍測試,祈禱不會出現問題吧。 */ //很好,,,測試可以工作!那麼繼續修改 } public int getAverageRating() { // return 4; return totalRating / numberOfRatings; // 剛才我們已經把常量替換掉了!測試是否還能工作呢?運作,,通過! /** 例子結束了,現在可以選擇一件事情,就是再添加一個測試,來驗證這個功能代碼是否真的被我們泛化了。 同時從這可以引申出,我們是否可以考慮在 return 4 的時候 就編寫這樣一個新的不同的平均分(比如測試平均分為5)的測試,然後 為了測試能夠工作,而對功能代碼進行泛化呢? 是以這就有了選擇,看你自己,是否願意在 return 4 這樣一個常量的時候去 編寫一個同樣目的但測試的期待結果不同的新測試來強制提醒你将功能代碼泛化; 還是說願意在之後寫一個為了檢驗是否泛化的新測試! */ } }
要明白:測試驅動開發的要點不在于采取了哪些措施,而在于能夠取得這些微小進步本身。(微小進步,有多微小呢?它甚至使得我們每一次的前進步伐控制在了幅度非常小,比如僅僅建立一個類的外殼、方法的外殼、字段的建立,這樣微小的前進步伐)因為如能夠做到很小的改進,也一定可以完成你所需要規模的改進。
從上面例子歸納出:使訓示條迅速變綠的三項政策:
- 僞實作:也就是那些微小進步的一個展現,通過建立出外殼,直接傳回測試所期待的一個常量值來讓測試通過,然後逐漸用變量取代它!
- 使用顯明實作:直接鍵入真正的代碼實作。
- 三角測量:目的是使得我們從不同角度去看待問題,進而得出結果,比如為了寫出判斷兩個對象相等的功能代碼,我們還可以測試其不相等的情況!
實踐中使用TDD時候,通常交替使用僞實作和顯明實作:當所有事情變得順暢時候,使用顯明實作吧;一旦測試未通過,意外出現了紅色訓示條,那就做好備份回到僞實作!
END
2019年11月3日,11點26分