BDD:Behavior-Driven Development 行爲驅動開發

咱們通常將測試放在項目的最後時刻進行,甚至在時間較緊時、預算超支,或者其餘緣由發生時會放棄測試。數據庫

項目的管理者好奇爲何開發者就是不能一開始就明白(需求、設計),而在系統有不少利益相關者而且不一樣的相關者對系統有不一樣的見解的時候,開發者(特別是在大型項目中),更容易變得迷糊,使得協商過程像盲人摸象同樣。app

每一個項目的開始,必然是有一個關於項目行爲表現、功能特色的討論會,由客戶或者其餘業務人員向開發團隊解釋他們就行想要什麼。(苦逼又使人討厭的策劃....)框架

有時候,這些交互、討論以敏捷開發形式表現;有時是設計文檔,就像去年查理斯-福克斯的博客所說的那樣;有時是由Keynote製做的流程圖或者模型;有時甚至是一個簡單的電話解釋而已。數據庫設計

僅經過這些溝通,開發者通常只是負責構建一個可以運行的系統而已,而這對於一個開發團隊來講,是遠遠不夠的。這(單純的溝通)對於大型系統的業餘開發人員來講尤爲困難。編輯器

爲何不進行測試?

通常存在一個爭議:若是客戶/業務人員一開始就對系統的行爲、特徵有充分的認知,那麼爲何每每要撤銷對這些功能、行爲進行測試?工具

答案可能很是簡單:測試通常被認爲是共享資產(對你們都有用的),也不被認爲是對項目開發有實際價值的。測試只對工程師有用或者只對特定的一些人有用。測試

那麼如何才能使得測試對你們都有價值呢?僅僅是列出系統的功能特性嗎?固然不是,咱們應該使用behavior-driven development (BDD)而不是僅僅是test-driven development (TDD)。編碼

BDD是什麼?

行爲驅動開發應該着眼於你的代碼所要實現的業務行爲,即「爲何要編寫這樣的代碼?」它能夠很好的支撐項目核心工做流程,特別是對於交叉功能的瞭解與實現。spa

敏捷BDD開發有很大的好處。當開發者和敏捷項目主或者業務分析師坐在一塊兒,將大概功能框框(具體如何實現由開發者在框內填寫)寫在白板上:設計

  1. 業務人員指定系統的行爲特性

  2. 開發者基於他們本身對系統的理解向業務人員提問,同時從開發者角度寫下其餘附加的行爲。

理想狀況下:項目的參與人員能根據當前系統行爲列表判斷新加入的功能行爲是否會破壞現有功能。
圖片描述
我發現這些簡單的行爲給了我一些約束,使得我能像一個開發者同樣思考:這些我已經實現的這些測試可以將個人實現代碼約束在一個規範之中。而那些功能代碼只需知足這些約束、規範,就能在協做開發中快速完成。

這種協做方法使得我更加專一於提供給最終用戶的功能特性,並且業務人員能夠在旁約束、糾正我對系統行爲的理解,而不是系統的具體實現。這就是BDD和TDD的突出區別。

BDD的一個例子

情景:你是負責開發企業會計系統的團隊一員,系統使用Rails框架實現。有一天,業務人員問你一個關於提醒模塊的功能:提醒用戶他們正在等待處理的發票。你坐下來和業務人員定義這個功能模塊。

你打開你的文本編輯器/筆記本,開始在上面畫上框框,每一個框表明用戶須要的功能行爲:

//爲每一個新支票添加一個提醒日期
it "adds a reminder date when an invoice is created"
//當提醒日期到來就發郵件提醒
it "sends an email to the invoice's account's primary contact after the reminder date has passed"
//若是用戶閱讀了郵件就給用戶打上標記
it "marks that the user has read the email in the invoice"

在開發中專一於系統行爲使得測試在驗證你所實現系統行爲是否正確中是十分有用的,而不只僅是編碼正確(沒有bug)。要注意的是,這種分析要用業務語言而不是實現系統所採用的具體開發語言。
你不須要將「發票屬於哪一個用戶」描述出來,由於開發團隊以外的人也並不關心這種關係。

有些開發者在討論/開發現場就寫出測試樣例,在系統中調用這些所要測試的方法,設置指望值,以下:

it "adds a reminder date when an invoice is created"  do
  current_invoice = create :invoice
  current_invoice.reminder_date.should == 20.days.from_now
end

這些測試樣例必然是運行失敗的,由於咱們尚未實現設置remind_date的代碼。

失敗的測試

我明白開發者爲何會寫失敗樣例測試,可是從業務人員的角度來講,這寫測試對他並沒有用處。一些業務人員可能會被這些測試細節、實現細節搞迷糊,甚至我學得一些開發知識後就插手開發人員的工做。(數據庫設計、代碼複用)

從個人經驗來開,若是開發者對於特定系統行爲寫出多行實現概要,業務人員會感到不耐煩,他們會以爲這是浪費他們的時間並不耐煩的急於闡釋他們假想的下一個系統行爲。

BDD和TDD的區別

如今咱們從另外一個角度看:使用TDD方法,而且寫出測試概要:

//建立支票後,過時日期=建立日期+20天
it "after_create an Invoice sets a reminder date to be creation + 20 business days"
//Account#primary_payment_contact返回支付聯繫人或者用戶項目管理者
it "Account#primary_payment_contact returns the current payment contact or the client project manager"
//InvoiceChecker#mailer 檢查是否過時,若是是,就發郵件提醒。
it "InvoiceChecker#mailer finds invoices that are overdue and sends the email"

這些測試是有用的,不過只是對一些人有用:工程師。BDD是用來溝通(交叉功能)項目成員的工具,包括開發者和業務人員。

經過暫時掛起(不實現)具體行爲,你能夠進行測試優先的開發。首先,編寫測試;接着,運行測試(固然是運行失敗的,由於咱們都還沒開始實現具體行爲);編寫行爲,使他能跑;修正,使他能正確運行。

BDD社區的不少工做和產品都使得測試中的斷言檢查讀起來向普通語言同樣。下面是一個刻板老套的RSpec測試:

a = 42
a.should == 42

這個格式使得結果易於閱讀和理解。但注意這不是咱們在此所應該作的,咱們應該儘快獲取系統行爲的準確描述,而且堅持「每一個系統行爲都要測試」的原則。而從以前白板上畫框框的工做,咱們基本可以知道系統行爲是什麼。

BDD不是修正編碼的奇特方式,它只是用來讓團隊成員(包含業務人員、顧客)對系統行爲進行溝通而已。

BDD是關於協做和溝通的

再回看剛纔的例子:企業會計系統。

你和業務人員討論項目的功能:你(開發者)從內部(各模塊是如何協做的)分析系統,而他們(業務人員)就從外部分析。

你會思考一些狀況而且並對系統分析師(業務人員)就一下狀況進行提問:

//默認的提醒日期是?在支票到期前的第幾天提醒?
* What's the default reminder date going to be? How many days before the invoice due date?
//這些天數是指天然日仍是工做日?
* Are those business days or just calendar days?
//若是這些支票所屬的帳號主沒有對應的聯繫方式,那該怎麼辦?
* What happens if there's not a primary contact associated with the account?

所以,使得業務人員理解你的問題是很是重要的,由於他們可能對具體開發缺少相應的知識。

有時候,BDD是一種有益於兩個部門(如策劃和開發)協做和溝通的工具,也是清晰劃分系統功能界限和對開發團隊(如預計開發時間)有更好估計的一種方法。
可能你意識到沒法從給定日期計算10天之後的日期(由於每月的天數都不同),那麼你就須要實現這個計數功能,而業務人員對這個計數功能可能並不關心。

開發者有對於具體開發的思考(好比你說的‘天’是什麼),業務人員也有他們的思考(如:請不要使用’過時’這個詞語了,有時候它有不一樣的意思)。所以,只由一方來考慮系統功能和測試就會抹殺掉另外一方的有價值的觀點。

固然若是業務人員或者客戶不能和開發者共處一室的時候,讓他們將指望的系統行爲和開發者本身的分析、理解寫在紙上也是一個有效的溝通方法。

相關文章
相關標籤/搜索