1. 程式人生 > >從 TDD 到 BDD

從 TDD 到 BDD

轉自http://www.cnblogs.com/lidaobing/archive/2010/07/18/1779987.html

最近在學 ruby, 也用了 rspec, 傳統的 xUnit 是 TDD 指導思想下的產物, 而 rspec 則算是 BDD (Behavior Driven Development) 影響下的產品。


TDD 和 BDD 區別究竟何在呢?

首先是思路上的區別, 傳統的 TDD 關注的是介面是否被正確地實現了, 所以通常每個介面有一個對應的單元測試函式。而 BDD 通常以類為單位, 關注一個類是否實現了文件定義的行為

具體從 rspec 的實現上來看, 主要有如下的不同

1. rspec 可以成為設計的一部分
 , 你在設計一個類的時候, 一般會先寫這個類需要實現哪些功能, 然後在逐個實現需求, 比如 XmlParser, 你會先計劃他有三個特性, 支援從字串初始化, 支援"=="符號, 支援序列化為字串, 這時候你就可以寫下如下的測試程式碼

# xml_parser_spec.rb
describe "XmlParser" do
  it "should support init with string"
  it "should support =="
  it "should can convert to string"end

此時執行如下的命令就可以看到你規劃的類行為
$ spec -f n xml_parser_spec.rb

XmlParser
  should support init with string (PENDING: Not Yet Implemented)
  should support == (PENDING: Not Yet Implemented)
  should can convert to string (PENDING: Not Yet Implemented)
...

上面的輸出可以清晰地看到 XmlParser 需要支援的功能。你不用把這些功能需求記在腦子裡, 也不放在你的 TODO 列表裡,直接放這兒就行了


2. 使用一個句子來描述你要測試的行為, 而不是簡單的重複被測試的介面名, 比如一個
典型的測試
it "should return [Miniblog] with different id" do
其中的 "should return [Miniblog] with different id" 就是這個測試的描述

3. 多級的 context, 便於將類的行為分到多個組, 同時每個組可以有不同的上下文環境(setUp+tearDown), 比如一個 xml parser, 如下所示的測試程式碼可以把行為分為兩組,在遇到合法資料時的行為以及遇到非法資料時的行為

describe XmlParser do
  context "with valid data" do
    before do
      @valid_data = "<a>123</a>"
    end
    ...
  end
  context "with invalid data" do
    before do
      @invalid_data = "<a>123</b>"
    end
    ...
  end   
end

4. 支援自動文件化, 在1裡已經可以看到 spec 支援生成一個簡略的文件來描述你的物件, 下面是一個比較長的例子用於描述 Douban::Authorize 的功能, 樹狀的結構把類的功能分到了多個小組


5. 表述更接近自然語言的習慣, 比如 xUnit 通常使用 assertEqual(a, 1), 而 rspec 經常使用 a.should == 1

相對於 TDD 來說, 這些都不是什麼革命性的突破。但是思路的轉變,能夠讓你的開發更流暢。

首先你在設計時就可以開始寫測試程式碼, 在開發完成後可以通過 rspec 生成的文件來快速瀏覽你是否完成了所有特性。這些性質都能讓測試驅動開發更容易推廣。從我的工作經驗來看, 由於種種原因 (比如沒有迭代週期, 缺乏 code review 制度, 沒有硬指標的覆蓋率要求...), 大家的測試程式碼寫得很少。而在 rspec 的幫助下, 直接看 rspec 生成的文件就可以督促大家補全測試。

轉自http://blog.csdn.net/ant_yan/article/details/7272612

敏捷開發有許多種方法,但不管採用任何一種,測試都是實施敏捷的基礎,及時的驗證程式碼的正確性,系統功能的健全與否,及時的反饋,及時的叫停……都是保證敏捷的基礎。所以大量的快速的自動化測試,才能保證敏捷開發在快速迭代中仍然不怎麼丟失軟體的質量。

所以,在敏捷開發裡一直都有一種說法叫“程式碼即文件”,而且測試程式碼也成了功能程式碼的使用文件。敏捷裡強調的TDD(Test-driven developmenet, 測試驅動開發),就主要體現了這種思想:根據設計編寫測試-> 實現設計的功能 -> 用測試程式碼驗證 -> 重構實現程式碼 -> 改善設計 -> 再次回到根據改善的設計編寫測試。反覆迴圈下去,就是TDD所倡導的流程。

TDD的好處:1. 能驅使系統最終的實現程式碼,都可以被測試程式碼所覆蓋到,也即“每一行程式碼都可測”。2. 測試程式碼作為實現程式碼的正確導向,最終演變為正確系統的行為,能讓整個開發過程更加高效。TDD的不足之處或者說還不夠完善的地方,是對設計和測試的編寫沒有一個明確的方針。作為整個迴圈中的嚮導部分,如何保證根據設計編寫的測試就是終端使用者所期望的系統行為?如果這一部分模糊了,那麼後續所有環節幾乎都要受到影響。所以,再次基礎上,敏捷社群又有人提出了BDD的概念,即“行為驅動開發”。

BDD(Behavior-driven development)把TDD中模糊的那一部分給明確了,強調開發、測試、BA、客戶等所有專案相關人員都用自然語言來描述系統的行為。大家看到的描述一致,讀到的內容一致,於是最終測試驅動開發產出的結果也應該是最符合使用者期望的。所以在BDD的倡導下,介紹了一種簡潔的類似自然語言叫Gherkin Language。下面看一個用Gherkin Language描述系統行為的例子:

[plain] view plaincopyprint?
  1. As a xxx [Role]  
  2. I want to xxx [Feature]  
  3. So that I can xxx[Benefit]  
  4. Scenario 1: create user  
  5. Given a admin log into the system  
  6. when he create a user with name 'mike'  
  7. then mike should be able to log into the system  

隨著BDD的出現和發展,使用大家都能輕易理解和認知的語言來描述系統的行為並建立User Story,TDD的反覆迴圈的流程也就能更順利的進行下去了。BDD的核心價值是體現在正確的對系統行為進行設計,所以它並非一種行之有效的測試方法。它強調的是系統最終的實現與使用者期望的行為是一致的、驗證程式碼實現是否符合設計目標。但是它本身並不強調對系統功能、效能以及邊界值等的健全性做保證,無法像完整的測試一樣發現系統的各種問題。

有種說法是BDD是TDD的進化,其實筆者看來,沒有孰優孰劣,它們的本質和目標都是一致的。只是在實施方法上,進行了不同的探討來完善整個敏捷開發的體系。如果BDD書寫的User Story或者叫測試用例,不能作為開發、測試和客戶等人共同參與和看到的一致性內容的話,那麼它的價值也幾乎得不到體現。另外一點,由於BDD不能代替完整的測試,旨在描述系統的行為,所以就像Gherkin Language的例子所體現的那樣,關鍵是“簡潔”,切忌囉嗦的想把每一步操作和任何情況都說得很清楚。

最後總結:TDD的迭代反覆驗證是敏捷開發的保障,但沒有明確如何根據設計產生測試,並保障測試用例的質量,而BDD倡導大家都用簡潔的自然語言描述系統行為的理念,恰好彌補了測試用例(即系統行為)的準確性。(不管以上理念是否先進,切忌盲從和濫用)