行為驅動開發(BDD)研究
1??????引言
在軟件工程中,行為驅動開發(BDD)是一種敏捷軟件開發過程,它鼓勵軟件項目中的開發人員、QA和非技術或業務參與者之間的協作,它鼓勵團隊使用對話和具體的例子來正式形成對應用程序應該如何運行的共識理解。它源于測試驅動開發(TDD)。?行為驅動開發將TDD的一般技術和原則與領域驅動設計和面向對象分析與設計的思想相結合,為軟件開發和管理團隊提供共享的工具和過程,以協同合作來開發軟件。
2??????行為驅動開發(BDD)
盡管BDD主要是一種關于軟件開發應該如何管理業務利益和技術洞察力的思想,但BDD的實踐確實假設了使用專門的軟件工具來支持開發過程,盡管這些工具通常是專門為BDD項目開發的,但也可以看作是支持測試驅動開發的工具化的專門形式。這些工具的作用是為BDD的核心主題(共識語言)的形成增加了自動化。
BDD在很大程度上是通過使用簡單的領域專用語言(DSL),并附以自然語言結構(例如,類似于英語的句子)來表達行為和預期結果,從而使得BDD的工程通俗易懂。長期以來,測試腳本一直是DSL的流行應用,其復雜程度不一。BDD被認為是一種有效的技術實踐,特別是當要解決的業務問題的?"問題空間?"比較復雜時,BDD的優勢就會非常明顯。
2.1????歷史
行為驅動開發是測試驅動開發的延伸:利用簡單的、特定領域的腳本語言進行開發。這些?DSL?將結構化的自然語言語句轉換為可執行的測試。?其結果是更接近于給定功能的驗收標準和用于驗證該功能的測試。因此,它是一般TDD測試的自然延伸。
BDD的重點是:
從哪里開始
哪些需要測試,哪些不需要測試
一次測試需要包含多少內容
如何調用測試
如何分析測試失敗的原因
BDD的核心是重新思考單元測試和驗收測試的方法,以避免可能產生的問題。例如,BDD建議單元測試的名稱應該是以條件動詞開頭的整句(例如英語中的?"應該"),并且應該按照業務價值的順序來寫。驗收測試應該使用用戶案例故事的標準敏捷框架來寫。"作為一個[角色],我希望有[這樣的功能]來獲得[什么好處]"。驗收標準應該用場景來寫,并以類的形式實現。?給定[初始場境],當[事件發生]時,然后[確保一些結果]。
基于此,很多人經過多年的發展,最終將BDD框架定義為軟件項目中的開發人員、QA和非技術人員或業務參與者的溝通和協作框架,在2009年11月在倫敦舉行的?"敏捷規范、BDD和測試eXchange "會議上,Dan North對BDD作了如下描述:
BDD是新一代、從外到內、基于拉取、多利益相關的、多規模、高自動化的敏捷方法。它是一個具有明確定義了產出的交互循環,從而實現了正常工作中的、經過測試的軟件產品的交付。
在2013年GOTO大會上接受Dan North采訪時,Liz Keogh將BDD定義為:
它用測試案例故事來探討應用程序的運行方式,并就這些案例故事展開深入討論。
Dan North?創建了一個?BDD?框架?JBehave,隨后又為?Ruby?創建了一個基于案例故事的?BDD?框架?RBehave,該框架后來被集成到?RSpec?項目中。?他還與?David Chelimsky、Aslak Helles?y?等人合作開發了?RSpec,還編寫了《The RSpec Book: Behaviour Driven Development with RSpec, Cucumber, and Friends》。RSpec中第一個基于案例故事的框架,后來被主要由Aslak Helles?y開發的Cucumber所取代。作為Cucumber測試框架的一部分,Capybara就是一款基于Web的測試的自動化軟件。
2.2????BDD的原則
測試驅動開發是一種軟件開發方法,其本質上說,對于每一個軟件單元,軟件開發人員必須:
該功能單元定義一個測試集。
讓測試失敗。
然后完成該功能單元的代碼實現。
最后驗證該功能單元的代碼實現是否使測試集成功。
上面這個定義是不具體的,因為它允許從高級軟件需求、低級技術細節或介于兩者之間抽取任何東西來進行測試。?因此,有一種觀點認為,BDD是TDD的繼續發展,它比TDD做出了更具體的選擇。
行為驅動開發規定,任何軟件單元的測試都應該以單元的期望行為來指定。借鑒敏捷軟件開發,這里的?"期望行為?"是由業務設定的需求組成的,也就是說,無論委托什么實體來構建軟件單元,都要有業務價值的期望行為。
2.2.1????行為規范
在上述基本原則之后,BDD的第二個選擇是關于如何指定所需的行為。在這個領域,BDD選擇使用一種半正式的行為規范格式,這種格式是從面向對象分析和設計領域的用戶案例故事規范中借鑒過來的。這種格式的場景方面可以看作是將豪爾邏輯應用到軟件單元的行為規范中,使用場景的領域語言進行行為規范處理。
BDD規定,業務分析人員和開發人員應該在這一領域進行合作,并且應該以用戶案例故事的形式來指定行為,每個用戶案例故事都被明確地寫在一個專門的文檔中。"每個用戶案例故事在某種程度上應該遵循以下結構:
l??一個明確的標題。
l??簡短的介紹部分,其結構如下:
n??As a (作為):將從該功能中受益的人或角色。
n??I Want(我想要):該功能。
n??So that(以便):該功能的好處或價值。
n??對每一個具體情節的描述,結構如下:
n??Given(給定):情景開頭的初始環境,用一個或多個分句表示。
n??when(當):觸發情節的事件,用一個或多個分句說明。
n??then(然后):預期的結果,用一個或多個分句說明。
BDD沒有任何正式的要求,但它堅持要求每個使用BDD的團隊都要有一個簡單的、標準化的格式來寫下用戶案例故事,其中包括上面列出的元素。然而,在2007年,Dan North提出了一個文本格式的模板,在不同的BDD軟件工具中得到了廣泛的應用。
標題:?退換貨入庫
作為一個店主。
我想在退貨或換貨的時候,將物品放回庫存。
這樣我就可以跟蹤庫存了。
情景一:退貨退款的商品應該加到庫存中。
鑒于之前有客戶在我這里買了一件黑色的毛衣
我有三件黑色的毛衣庫存。
當他們把黑色的毛衣退回來要求退款。
那么我的庫存中應該有四件黑色毛衣。
情景二:退換貨的商品應該更新庫存。
考慮到之前有客戶從我這里買了一件藍色的衣服
而我有兩件藍色的衣服在庫存中
和三件黑色服裝的庫存。
當他們把藍色的衣服換成黑色的衣服時。
那我應該有三件藍色的衣服在庫存中
和兩件黑色服裝的庫存。
上述場景是以聲明性而非強制性的方式來表達的,在業務語言中,沒有提及交互發生的UI元素。
這種格式被稱為Gherkin語言,其語法類似于上面的例子。然而,Gherkin這個詞是Cucumber、JBehave、Lettuce、behave和Behat等軟件工具所特有的。
2.2.2????規范作為一種共識語言
行為驅動開發從領域驅動設計中借用了泛在語言的概念,泛在語言是一種(半)正式的語言,它是軟件開發團隊的所有成員--包括軟件開發人員和非技術人員--共享的語言,該語言是所有團隊成員共同使用和開發的,是討論相關軟件領域的共同手段,這樣,BDD就成為軟件項目中所有不同角色之間溝通的載體。
軟件開發中常見的風險包括開發人員和業務利益相關者之間的溝通斷裂,BDD將期望的行為規范作為項目團隊成員的一種共識語言。這也是BDD堅持使用半形式化的行為規范語言的原因:某種形式化是成為一種共識語言的要求。此外,擁有這樣一種共識語言,可以創建一個規范的領域模型,這樣規范就可以在形式上進行推理。這個模型也是支持BDD的不同軟件工具的基礎。
上面給出的例子為一個正在開發的軟件系統建立了一個用戶案例故事。這個用戶案例故事確定了一個利益相關者、一個業務效果和一個業務價值。它還描述了幾個場景,每個場景都有一個前提條件、觸發器和預期結果。這些部分中的每一個都是由語言中比較正式的部分準確地標識出來的(例如,給定(Given)這個詞可能被認為是一個關鍵詞),因此,可以通過理解通用語言中的正式部分的工具以某種方式進行處理。
大多數?BDD?應用程序使用基于文本的?DSL?和規范方法。然而,集成場景的圖形化建模在實踐中也得到了成功的應用,例如,為了測試的目的而設計出的圖形化建模。
2.3????專業化的工具支持
與測試驅動的設計實踐類似,行為驅動的開發假定在項目中使用專門的支持工具。就像BDD在許多方面是TDD的一個更具體的版本一樣,BDD的工具與TDD的工具類似,但對開發人員提出了比基本的TDD工具更多的要求。
2.3.1????工具原則
原則上,支持BDD的工具是一個軟件的測試框架,與支持TDD的工具很像。?然而,TDD工具在允許指定測試的內容方面往往是相當自由的,而BDD工具則與前面討論過的共識語言的定義有關。
正如前面所討論的那樣,共識語言允許業務分析人員以一種也會被開發人員理解的方式寫下行為需求。BDD?支持工具化的原則是讓這些相同的需求文檔作為測試的集合直接執行。如果因為與實現規范執行的技術工具有關的原因而無法實現,那么我們需要的是:要么改變行為需求的編寫風格,要么就必須改變工具。每個工具的行為需求的具體實現方式不盡相同,但敏捷實踐得出了以下一般流程:
n??通過工具讀取一個規范文檔。
n??該工具可以直接理解共識語言中完全正式的部分(如上面例子中的給定(Given)關鍵字)。在此基礎上,工具將每個場景分解成有意義的子句。
n??場景中的每一個單獨的子句都被轉化為用戶案例故事測試的某種參數。這一部分需要軟件開發人員針對項目的具體工作來進行。
n??然后,框架會根據每個場景的參數來執行每個場景的測試。
Dan North開發了許多支持BDD的框架(包括JBehave和RBehave),其操作是基于他建議的記錄用戶案例故事的模板,這些工具使用文本描述的用例,其他幾個工具(如CBehave)也紛紛效仿。然而,這種格式并不是必須的,所以其他工具也使用了其他格式。例如,Fitnesse(Fitnesse是圍繞決策表構建的)也推出了BDD的支持。
2.3.2????工具化實例
當前,有幾個不同平臺和編程語言的BDD軟件工具在項目中使用的例子可供參考。
最著名的可能是JBehave,它由Dan North、Elizabeth Keogh和其他幾個人開發的。以下是該項目的一個例子:
考慮一個生命游戲的實現。一個領域專家(或業務分析員)可能想指定當有人在設置游戲網格的起始配置時應該發生什么。要做到這一點,他可能想舉例說明一個人在切換單元格時所采取的一些步驟。跳過敘述部分,他可能會把下面的場景寫成一個純文本文檔(這是JBehave讀取的輸入文檔的類型):
Given給定一個5乘5的游戲 When當我在(3,2)切換單元格時 Then那么網格應該是這樣的 ..... ..... ..... ..X.. ..... When當我在(3,?1)處切換單元格時 Then那么網格應該是這樣的 ..... ..... ..... ..X.. ..X.. When當我在(3,?2)處切換單元格時 Then那么網格應該是這樣的 ..... ..... ..... ..... ..X..
JBehave可以識別出Given(作為定義場景開始的前提條件),When(作為事件觸發器)和Then(作為后置條件,必須被驗證為觸發器之后的動作結果)。基于此,JBehave能夠讀取包含場景的文本文件,并將其解析成子句(一個設置子句和三個帶可驗證條件的事件觸發器)。然后JBehave將這些子句傳遞給能夠設置測試、響應事件觸發器并驗證結果的代碼。這些代碼必須由項目團隊的開發人員編寫(用Java編寫,因為JBehave是基于這個平臺)。在這種情況下,代碼可能看起來是這樣的:
private?Game?game; private?StringRenderer?renderer; ? @Given("a?$width?by?$height?game") public?void?theGameIsRunning(int?width,?int?height)?{ ????game?=?new?Game(width,?height); ????renderer?=?new?StringRenderer(); ????game.setObserver(renderer); } ???? @When("I?toggle?the?cell?at?($column,?$row)") public?void?iToggleTheCellAt(int?column,?int?row)?{ ????game.toggleCellAt(column,?row); } ? @Then("the?grid?should?look?like?$grid") public?void?theGridShouldLookLike(String?grid)?{ ????assertThat(renderer.asString(),?equalTo(grid)); }
代碼中的每一種類型的子句都有一個方法。JBehave將通過使用注釋來識別哪個方法與哪個子句一起使用,并在運行場景時按順序調用每個方法。場景中每個子句中的文本應該與代碼中給出的模板文本相匹配(例如,場景中的Given后面應該有一個形式為?" X乘以Y的游戲?"的子句)。JBehave支持子句與模板的匹配,并且內置支持從模板中選取子句并將其作為參數傳遞給測試代碼中的方法。測試代碼為每個子句類型提供了場景中的每個子句類型的實現,它與被測代碼進行交互,并根據場景執行測試。在本例中:
n??TheGameIsRunning方法通過設置初始游戲網格對Given子句做出反應。
n??iToggleTheCellAt方法通過觸發該子句中描述的切換事件對When子句做出反應。
n??TheGridShouldLookLike方法通過比較游戲網格的狀態和場景中的預期狀態來對Then子句做出反應。
這段代碼的主要功能是在有案例故事的文本文件和被測代碼之間架起一個橋梁。?需要注意的是,測試代碼可以訪問被測代碼(比如上面的游戲),這點很容易理解。測試代碼必須要簡單,否則,開發者最終不得不為自己的測試代碼再編寫測試代碼。
最后,為了運行測試,JBehave需要一些管道代碼來識別包含場景的文本文件,并將依賴關系(如上例中的游戲)注入到測試代碼中。這個管道代碼在這里不做說明,因為它是JBehave的技術要求,與BDD式測試的原理沒有直接關系。
2.4????案例故事與需求的對比
行為驅動開發的一個單獨的子類別是使用需求作為輸入語言,而不是用戶案例故事。?這種風格的一個例子是RSpec工具,它也是由Dan North最初開發的。需求工具不使用用戶案例故事作為測試場景的輸入格式,而是使用功能需求來測試被測單元。這些需求通常比用戶案例故事更具有技術性,而且通常比用戶案例故事更不方便與業務人員溝通。?來看一個堆棧需求的例子:
需求:?Stack ? When?一個新的Stack被創建 Then?它是空的 ? When?一個新元素被添加到Stack Then?這個新元素會在Stack的頂部 ? When?一個Stack有?N?個元素時? And?元素?E?在?Stack?頂部 Then?一個彈出操作會返回?E And?新的Stack的元素個數會變為?N-1
這樣的需求雖然明確指定了被測組件的行為,但對業務用戶來說意義不大。因此,在BDD實踐中,基于需求的測試被看作是對基于案例故事的測試的一種補充,并在較低的層次上使用。需求測試通常被看作是對自由式單元測試的替代。
像RSpec和JDave這樣的需求測試工具在性質上與JBehave等工具有些不同。因為它們被視為基本的單元測試工具(如JUnit)的替代品,所以這些工具傾向于放棄案例故事和測試代碼的分離,而傾向于將需求直接嵌入測試代碼中。例如,一個hashtable的RSpec測試是這樣的:
describe?Hash?do ??let(:hash)?{?Hash[:hello,?'world']?} ? ??it?{?expect(Hash.new).to?eq({})?} ? ??it?"hashes?the?correct?information?in?a?key"?do ????expect(hash[:hello]).to?eq('world') ??end ? ??it?'includes?key'?do ????hash.keys.include?(:hello).should?be?true ??end end
這個例子顯示了如何把可讀語言的需求嵌入到可執行代碼中。在這種情況下,工具的選擇是通過添加名為該需求的方法,將需求語言轉化化為測試代碼的語言。此外,這里也要注意需求的前提條件概念,也就是這個需求能夠滿足的前提條件。
上面測試的結果差不多是這樣的:
Hash ????should?eq?{} ????includes?key ????hashes?the?correct?information?in?a?key
2.5????三駕馬車
三駕馬車,是三個角色,是指產品負責人與不同的利益相關者(如QA和開發團隊),?他們會以實例需求的形式討論需求的會議。這個討論的關鍵目標是通過對話并找出任何缺失的需求。這個討論也為QA、開發團隊和產品負責人提供了一個平臺,讓QA、開發團隊和產品負責人可以互相交流和聽取對方的意見,以豐富需求,并確定他們要做的產品方向是否正確。
2.5.1????業務
業務用戶的作用只是定義問題(而不是提出任何解決方案)。
2.5.2????開發
開發團隊的作用是提出解決問題的方法。
2.5.3????測試
測試團隊的角色是質疑解決方案,通過What-If場景,提出盡可能多的不同的可能性,進行頭腦風暴式的思考,并幫助解決方案更精確地處理問題。
3??????參考
https://www.agilealliance.org/glossary/bdd/
https://medium.com/javascript-scene/behavior-driven-development-bdd-and-functional-testing-62084ad7f1f2
https://blog.testlodge.com/what-is-bdd/
https://cucumber.io/docs/bdd/
https://inviqa.com/blog/bdd-guide
https://en.wikipedia.org/wiki/Behavior-driven_development
軟件開發
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。