
- 行為驅動開發
- BDD - 首頁
- BDD - 簡介
- BDD - 測試驅動開發
- BDD - 以BDD方式進行TDD
- BDD - 示例規範
- BDD - 工具
- BDD - Cucumber
- BDD - Gherkin
- BDD - SpecFlow
- BDD 有用資源
- BDD - 快速指南
- BDD - 有用資源
- BDD - 討論
行為驅動開發 - 快速指南
行為驅動開發 - 簡介
行為驅動開發 (BDD) 是一種軟體開發流程,最初起源於測試驅動開發 (TDD)。
根據負責 BDD 演進的 Dan North 的說法,“BDD 是在多個層面上使用示例來建立共享理解並揭示不確定性,以交付有意義的軟體。”
BDD 使用示例來說明系統的行為,這些示例以每個人參與開發都能理解的易讀語言編寫。這些示例包括 -
轉換為可執行的規範。
用作驗收測試。
BDD – 關鍵特性
行為驅動開發側重於 -
提供共享流程和共享工具,促進軟體開發人員、業務分析師和利益相關者之間的溝通,以協作進行軟體開發,目標是交付具有業務價值的產品。
系統應該做什麼,而不是如何實現它。
提供更好的可讀性和可見性。
不僅驗證軟體的工作原理,還驗證它是否滿足客戶的期望。
BDD 的起源
如果缺陷沒有在正確的時間被檢測到並及時修復,則修復缺陷的成本會成倍增加。請考慮以下示例。

這表明,除非正確獲取需求,否則在後期階段因誤解需求而導致的缺陷修復成本將會很高。此外,最終產品可能無法滿足客戶的期望。
當務之急是一種開發方法,該方法 -
基於需求。
在整個開發過程中關注需求。
確保滿足需求。
BDD 是一種可以滿足上述需求的開發方法。因此,行為驅動開發 -
推匯出系統不同預期行為的示例。
能夠使用業務領域術語以一種語言編寫示例,以確保所有參與開發的人員(包括客戶)都能輕鬆理解。
透過對話不時與客戶確認示例。
在整個開發過程中關注客戶需求(示例)。
使用示例作為驗收測試。
BDD 實踐
BDD 的兩個主要實踐是 -
示例規範 (SbE)
測試驅動開發 (TDD)
示例規範
示例規範 (SbE) 使用對話中的示例來說明業務規則以及要構建的軟體的行為。
示例規範使產品負責人、業務分析師、測試人員和開發人員能夠消除對業務需求的常見誤解。
測試驅動開發
在 BDD 的上下文中,測試驅動開發將示例轉換為人類可讀的可執行規範。
開發人員使用這些規範作為指南來實現新功能的增量。這導致程式碼庫精簡,並提供一套自動化迴歸測試,從而在軟體的整個生命週期內保持較低的維護成本。
敏捷 BDD
在敏捷軟體開發中,BDD 方法用於達成對未決規範的共同理解。
在敏捷 BDD 中執行以下步驟 -
開發人員和產品負責人協作在純文字編輯器中編寫未決規範。
產品負責人指定他們期望系統具有的行為。
開發人員
用這些行為細節填充規範。
根據他們對系統的理解提出問題。
考慮當前的系統行為,以檢視新功能是否會破壞任何現有功能。
敏捷宣言和 BDD
敏捷宣言宣告以下內容 -
我們正在透過實踐和幫助他人實踐來發現更好的軟體開發方法。透過這項工作,我們已經認識到以下價值 -
個體和互動 - 高於流程和工具
可工作的軟體 - 高於詳盡的文件
客戶合作 - 高於合同談判
響應變化 - 高於遵循計劃
也就是說,雖然右側的專案有價值,但我們更重視左側的專案。
BDD 與敏捷宣言的對應關係如下 -
敏捷宣言 | BDD 對應關係 |
---|---|
個體和互動高於流程和工具。 | BDD 是關於進行對話的。 |
可工作的軟體高於詳盡的文件。 | BDD 側重於簡化建立具有業務價值的軟體。 |
客戶合作高於合同談判。 | BDD 側重於基於想法的場景,並在開發過程中與客戶進行持續溝通。它不基於任何承諾。 |
響應變化高於遵循計劃。 | BDD 側重於持續溝通和協作,這有助於吸收變化。 |
BDD - 測試驅動開發
當您檢視任何關於行為驅動開發的參考時,您會發現諸如“BDD 派生自 TDD”、“BDD 和 TDD”之類的短語。要了解 BDD 如何產生、為什麼說它派生自 TDD 以及 BDD 和 TDD 是什麼,您必須瞭解 TDD。
為什麼要測試?
首先,讓我們深入瞭解測試的基本原理。測試的目的是確保構建的系統按預期工作。請考慮以下示例。

因此,根據經驗,我們瞭解到在引入缺陷時立即發現並修復它將是經濟高效的。因此,有必要在開發和測試的每個階段編寫測試用例。這就是我們傳統的測試實踐所教給我們的,通常稱為儘早測試。

這種測試方法稱為最後測試方法,因為測試是在一個階段完成後進行的。
最後測試方法的挑戰
在軟體開發專案中,最後測試方法已經沿用了相當長一段時間。然而,實際上,由於這種方法需要等到特定階段完成後才能進行測試,因此常常會被忽視,原因是 -
階段完成的延遲。
時間安排緊張。
專注於按時交付,跳過測試。
此外,在最後測試方法中,開發人員應該進行的單元測試常常會被跳過。發現的各種原因都基於開發人員的心態 -
他們是開發人員,而不是測試人員。
測試是測試人員的責任。
他們擅長編碼,他們的程式碼不會有缺陷。
這導致 -
影響交付產品的質量。
僅將質量責任歸於測試人員。
交付後修復缺陷的成本很高。
無法獲得客戶滿意度,這也意味著失去回頭客,從而影響信譽。
這些因素要求轉變正規化,專注於測試。結果是首要測試方法。
首要測試方法
首要測試方法將自內而外(編寫程式碼然後測試)的開發方式替換為自外而內(編寫測試然後編寫程式碼)的開發方式。
此方法已納入以下軟體開發方法(也屬於敏捷方法) -
極限規劃 (XP)。
測試驅動開發 (TDD)。
在這些方法中,開發人員在編寫程式碼模組的任何一行程式碼之前,都會設計並編寫該程式碼模組的單元測試。然後,開發人員建立程式碼模組,目標是透過單元測試。因此,這些方法使用單元測試來驅動開發。
需要注意的基本點是,目標是基於測試的開發。
紅-綠-重構迴圈
測試驅動開發用於開發由單元測試引導的程式碼。
步驟 1 - 考慮要編寫的程式碼模組。
步驟 2 - 編寫測試
步驟 3 - 執行測試。
測試失敗,因為程式碼尚未編寫。因此,步驟 2 通常稱為編寫測試以失敗。
步驟 4 - 編寫儘可能少的程式碼以透過測試。
步驟 5 - 執行所有測試以確保它們都仍然透過。單元測試是自動化的,以促進此步驟。
步驟 6 - 重構。
步驟 7 - 對下一個程式碼模組重複步驟 1 到步驟 6。
每個迴圈都應該非常短,典型的一個小時應該包含許多迴圈。

這也被稱為紅-綠-重構迴圈,其中 -
紅色 - 編寫失敗的測試。
綠色 - 編寫程式碼以透過測試。
重構 - 刪除重複項並將程式碼改進到可接受的標準。
TDD 流程步驟
下面說明了 TDD 流程的步驟。

TDD 的優勢
測試驅動開發的好處或優勢包括 -
開發人員需要首先了解期望的結果是什麼以及如何在建立程式碼之前對其進行測試。
只有當測試透過並且程式碼經過重構後,某個元件的程式碼才算完成。這確保了在開發人員轉到下一個測試之前進行測試和重構。
由於在每次重構後都會執行單元測試套件,因此每個元件仍然可以工作的反饋是持續的。
單元測試充當始終是最新的動態文件。
如果發現缺陷,開發人員會建立一個測試來揭示該缺陷,然後修改程式碼以使測試透過並修復缺陷。這減少了除錯時間。所有其他測試也會執行,並且當它們透過時,確保現有的功能沒有被破壞。
開發人員可以隨時做出設計決策並重構,並且測試的執行確保系統仍在工作。這使得軟體易於維護。
開發人員有信心進行任何更改,因為如果更改影響任何現有功能,則可以透過執行測試來揭示相同的功能,並且可以立即修復缺陷。
在每次後續測試執行中,所有先前的缺陷修復也將得到驗證,並且減少了相同缺陷的重複。
由於大部分測試是在開發過程中完成的,因此交付前的測試時間縮短了。
TDD的缺點
起點是使用者故事,描述系統的行為。因此,開發人員經常面臨以下問題:
何時測試?
測試什麼?
如何知道是否滿足規範?
程式碼是否交付了業務價值?
關於TDD的誤解
行業中存在以下誤解,需要澄清。
誤解 | 澄清 |
---|---|
TDD完全是關於測試和測試自動化。 | TDD是一種使用測試優先方法的開發方法。 |
TDD不涉及任何設計。 | TDD包括基於需求的關鍵分析和設計。設計在開發過程中出現。 |
TDD僅在單元級別。 | TDD可用於整合和系統級別。 |
TDD不能用於傳統的測試專案。 | TDD隨著極限程式設計而流行,並被用於其他敏捷方法。但是,它也可以用於傳統的測試專案。 |
TDD是一種工具。 | TDD是一種開發方法,每次新的單元測試通過後,都會將其新增到自動化測試套件中,因為每次新增新程式碼或修改現有程式碼以及每次重構後都需要執行所有測試。 因此,支援TDD的測試自動化工具促進了這一過程。 |
TDD意味著將驗收測試交給開發人員。 | TDD並不意味著將驗收測試交給開發人員。 |
驗收TDD
驗收測試驅動開發(ATDD)在開發早期建立使用者故事期間定義驗收標準和驗收測試。ATDD側重於客戶、開發人員和測試人員之間的溝通和共同理解。
ATDD中的關鍵實踐如下:
討論現實世界中的場景,以建立對領域的共同理解。
使用這些場景得出驗收標準。
自動化驗收測試。
將開發重點放在這些測試上。
使用測試作為即時規範來促進更改。
使用ATDD的好處如下:
需求明確且沒有功能差距。
其他人瞭解開發人員預見的特殊情況。
驗收測試指導開發。

TDD與BDD
根據Dan North的說法,程式設計師在執行測試驅動開發時通常會遇到以下問題:
從哪裡開始
測試什麼和不測試什麼
一次測試多少
如何稱呼他們的測試
如何理解測試失敗的原因
所有這些問題的解決方案都是行為驅動開發。它從既定的敏捷實踐中發展而來,旨在使它們更容易被不熟悉敏捷軟體交付的團隊所訪問和使用。隨著時間的推移,BDD已經發展到涵蓋敏捷分析和自動化驗收測試的更廣泛的範圍。
TDD和BDD之間的主要區別在於:
TDD描述了軟體的工作原理。
另一方面,BDD:
描述終端使用者如何使用軟體。
促進協作和溝通。
強調系統行為的示例。
旨在從示例中獲得可執行的規範
BDD - 以BDD方式進行TDD
在TDD中,“驗收測試”一詞具有誤導性。驗收測試實際上代表了系統的預期行為。在敏捷實踐中,強調整個團隊的協作以及與客戶和其他利益相關者的互動。這導致了使用每個人都容易理解的術語的必要性。
TDD讓你思考所需的行為,因此“行為”一詞比“測試”一詞更有用。BDD是測試驅動開發,其詞彙側重於行為而不是測試。
用Dan North的話說,“我發現從思考測試到思考行為的轉變是如此深刻,以至於我開始將TDD稱為BDD或行為驅動開發。”TDD關注某件事如何工作,BDD關注我們為什麼要構建它。
BDD回答了開發人員經常面臨的以下問題:
問題 | 答案 |
---|---|
從哪裡開始? | 自頂向下 |
測試什麼? | 使用者故事 |
不測試什麼? | 其他任何事 |
這些答案導致以下故事框架:
故事框架
作為一個[角色]
我想要[功能]
以便[利益]
這意味著,“當功能被執行時,產生的利益歸屬於扮演角色的人。”
BDD進一步回答了以下問題:
問題 | 答案 |
---|---|
一次測試多少? | 非常少,重點突出 |
如何稱呼他們的測試? | 句子模板 |
如何理解測試失敗的原因 | 文件 |
這些答案導致以下示例框架:
示例框架
給定一些初始上下文,
當事件發生時,
然後確保一些結果。
這意味著,“從初始上下文開始,當發生特定事件時,我們知道應該是什麼結果。”
因此,示例顯示了系統的預期行為。這些示例用於說明系統的不同場景。
故事和場景
讓我們考慮Dan North關於ATM系統的以下示例。
故事
作為一個客戶,
我想要從ATM機上取款,
以便我不必在銀行排隊。
場景
這個故事有兩種可能的場景。
場景1 - 賬戶有餘額
給定賬戶有餘額
並且卡有效
並且出納機裡有現金
當客戶請求現金時
然後確保賬戶被扣款
並且確保現金被髮放
並且確保卡被退回
場景2 - 賬戶透支超過透支限額
給定賬戶透支
並且卡有效
當客戶請求現金時
然後確保顯示拒絕訊息
並且確保現金未被髮放
並且確保卡被退回
這兩個場景中的事件相同,但上下文不同。因此,結果也不同。
開發週期
BDD的開發週期採用自頂向下的方法。
步驟1 - 編寫一個高階(外部)業務價值示例(使用Cucumber或RSpec/Capybara),使其變為紅色。(RSpec在Ruby語言中生成BDD框架)
步驟2 - 為第一步實現編寫一個較低級別(內部)RSpec示例,使其變為紅色。
步驟3 - 實現透過該較低級別示例所需的最小程式碼,使其變為綠色。
步驟4 - 編寫下一個較低級別RSpec示例,推動透過步驟1,使其變為紅色。
步驟5 - 重複步驟3和步驟4,直到步驟1中的高階示例變為綠色。
注意 - 應牢記以下幾點:
紅/綠狀態是許可權狀態。
當您的低階測試為綠色時,您有權編寫新示例或重構現有實現。在重構的上下文中,您不得新增新功能/靈活性。
當您的低階測試為紅色時,您只有權編寫或更改實現程式碼以使現有測試變為綠色。您必須抵制編寫程式碼以透過您尚未存在的下一個測試或實現您認為很好的功能(客戶不會提出)的衝動。
BDD - 示例規範
根據“基於示例的規範”的作者Gojko Adzic,“基於示例的規範是一組流程模式,可以促進軟體產品的變更,以確保有效地交付正確的產品。”
基於示例的規範是一種協作方法,用於定義軟體產品的需求和麵向業務的功能測試,該方法基於使用現實示例而不是抽象陳述來捕獲和說明需求。
基於示例的規範 - 概述
基於示例的規範的目的是專注於優先順序排序、可驗證的業務需求的開發和交付。雖然基於示例的規範本身的概念相對較新,但它只是對現有實踐的重新表述。
它支援一個非常具體、簡潔的詞彙,稱為普遍語言,該語言:
啟用可執行的需求。
由團隊中的每個人使用。
由跨職能團隊建立。
捕捉每個人的理解。
基於示例的規範可以直接用作構建反映業務領域的自動化測試的輸入。因此,基於示例的規範的重點在於構建正確的產品和正確地構建產品。
基於示例的規範的目的
基於示例的規範的主要目的是構建正確的產品。它側重於共享理解,從而建立單一的事實來源。它能夠自動化驗收標準,以便重點放在缺陷預防而不是缺陷檢測上。它還提倡儘早測試以儘早發現缺陷。
SbE的使用
基於示例的規範用於說明描述業務價值的預期系統行為。插圖是透過具體和現實生活中的例子來實現的。這些示例用於建立可執行的需求,這些需求:
無需翻譯即可測試。
捕獲在即時文件中。
以下是我們使用示例來描述特定規範的原因:
它們更容易理解。
它們更難誤解。
SbE的優勢
使用基於示例的規範的優勢在於:
質量提高
減少浪費
降低生產缺陷的風險
重點工作
可以更安全地進行更改
提高業務參與度
SbE的應用
基於示例的規範應用於:
複雜的業務或複雜的組織。
不適用於純粹的技術問題。
不適用於以UI為中心的軟體產品。
也可應用於遺留系統。
SbE和驗收測試
基於示例的規範在驗收測試方面的優勢在於:
一個插圖同時用於詳細需求和測試
專案的進度以驗收測試為依據:
每個測試都是為了測試一種行為。
測試要麼透過行為,要麼不透過。
測試透過表示特定行為已完成。
如果一個需要完成100種行為的專案完成了60種行為,那麼它就完成了60%。
測試人員從修復缺陷轉向預防缺陷,併為解決方案的設計做出貢獻。
自動化允許即時瞭解需求變更對解決方案的影響。
基於示例的規範 - 對不同角色的意義
基於示例的規範的目的是促進整個團隊(包括客戶)在整個專案中的協作,以交付業務價值。為了更好地理解,每個人都使用相同的詞彙。
角色 | SbE的使用 |
---|---|
業務分析師 |
|
開發人員 |
|
測試人員 |
|
所有人 |
|
SbE – 一套流程模式
正如我們在本章開頭所看到的,基於示例的規範 (Specification by Example) 被定義為一套流程模式,這些模式促進軟體產品的變更,以確保高效地交付正確的產品。
這些流程模式包括:
協作規範
使用示例說明規範
細化規範
自動化示例
頻繁驗證
活文件
協作規範
協作規範的目標是:
使團隊中的各個角色擁有共同的理解和共享的詞彙。
讓每個人都參與到專案中,以便他們能夠貢獻他們對功能的不同視角。
確保功能的共享溝通和所有權。
這些目標在規範研討會(也稱為“三位一體”會議)中實現。“三位一體”是指業務分析師 (BA)、質量保證 (QA) 和開發人員。儘管專案中還有其他角色,但這三位將負責並對從功能定義到交付負責。
在會議期間:
業務分析師 (BA) 展示新功能的需求和測試。
三位一體 (BA、開發人員和 QA) 討論新功能並審查規範。
QA 和開發人員還識別缺失的需求。
三位一體
利用共享模型使用普遍語言。
使用領域詞彙(如果需要,維護詞彙表)。
尋找差異和衝突。
此時不要跳到實現細節。
就功能是否已充分指定達成共識。
共享的需求和測試所有權有助於提高規範的質量。
需求以場景的形式呈現,這些場景提供了明確、無歧義的需求。場景是從使用者角度來看系統行為的一個示例。
使用示例說明規範
場景使用 Given-When-Then 結構進行指定,以建立可測試的規範:
給定 <某些前提條件>
並且 <其他前提條件> 可選
當 <某個動作/觸發器發生>
那麼 <某些後置條件>
並且 <其他後置條件> 可選
此規範是系統行為的一個示例。它也代表了系統的驗收標準。
團隊討論這些示例,並納入反饋,直到達成一致意見,認為這些示例涵蓋了功能的預期行為。這確保了良好的測試覆蓋率。
細化規範
要細化規範,
編寫示例時要準確。如果某個示例變得複雜,則將其拆分為更簡單的示例。
專注於業務視角,避免技術細節。
考慮正負條件。
遵守特定領域的詞彙。
與客戶討論示例。
選擇對話來完成此操作。
僅考慮客戶感興趣的示例。這使得僅生成所需的程式碼成為可能,並避免覆蓋可能不需要的每種可能的組合。
為了確保場景透過,該場景的所有測試用例都必須透過。因此,增強規範以使其可測試。測試用例可以包括各種範圍和資料值(邊界和角落情況),以及導致資料變化的不同業務規則。
指定其他業務規則,例如複雜計算、資料操作/轉換等。
將非功能場景(例如效能、負載、可用性等)包含為基於示例的規範。
自動化示例
自動化層需要保持非常簡單——只需將規範連線到被測系統即可。您可以為此使用工具。
使用領域特定語言 (DSL) 執行測試自動化,並顯示輸入和輸出之間的清晰連線。專注於規範,而不是指令碼。確保測試精確、易於理解且可測試。
頻繁驗證
在每次更改(新增/修改)時將示例驗證包含在您的開發管道中。有許多技術和工具可以(並且應該)被採用來幫助確保產品的質量。它們圍繞三個關鍵原則展開——**儘早測試、測試好**和**經常測試**。
頻繁執行測試,以便您可以識別薄弱環節。代表行為的示例有助於跟蹤進度,並且只有在相應的測試通過後,才認為行為已完成。
活文件
保持規範儘可能簡單和簡短。組織規範並在工作進行時對其進行演變。使團隊中的所有人員都能訪問文件。
基於示例的規範流程步驟
插圖顯示了基於示例的規範中的流程步驟。

反模式
反模式是軟體開發中某些被認為是不良程式設計實踐的模式。與設計模式相反,設計模式是針對常見問題的常見方法,這些方法已被形式化並且通常被認為是良好的開發實踐,而反模式則相反,並且是不希望的。
反模式會導致各種問題。
反模式 | 問題 |
---|---|
缺乏協作 |
|
不知道程式碼何時完成 |
|
過於詳細或過於以 UI 為中心的示例 |
|
低估所需的工作量 |
|
解決問題的方案 - 質量
可以透過關注反模式來確保質量。為了最大程度地減少反模式造成的問題,您應該:
一起使用示例進行規範。
清理和改進示例。
編寫滿足示例的程式碼。
自動化示例並部署。
對每個使用者故事重複此方法。
解決由於反模式造成的問題意味著遵守:
協作。
專注於“什麼”。
專注於業務。
做好準備。
讓我們瞭解上述內容的含義。
協作
在協作中:
業務人員、開發人員和測試人員從各自的角度提供輸入。
自動化的示例證明團隊構建了正確的東西。
該流程比測試本身更有價值。
專注於“什麼”
您必須專注於“什麼”這個問題。在專注於“什麼”時:
不要試圖涵蓋所有可能的情況。
不要忘記使用不同型別的測試。
保持示例儘可能簡單。
示例應該易於系統使用者理解。
工具不應該在研討會中發揮重要作用。
專注於業務
要專注於業務:
將規範保持在業務意圖層面。
讓業務參與建立和審查規範。
將所有細節隱藏在自動化層中。
做好準備
為以下情況做好準備:
即使團隊實踐發生變化,好處也不會立即顯現。
引入 SbE 具有挑戰性。
需要時間和投資。
自動化測試並非免費。
工具
基於示例的規範不需要使用工具,儘管在實踐中可以使用多種工具。即使不使用工具,也有一些案例成功地遵循了基於示例的規範。
以下工具支援基於示例的規範:
Cucumber
SpecFlow
Fitnesse
Jbehave
Concordion
Behat
Jasmine
Relish
Speclog
行為驅動開發 - 工具
開發團隊經常誤以為 BDD 是一個工具框架。實際上,BDD 是一種開發方法,而不是工具框架。但是,與其他開發方法一樣,BDD 也有一些工具。
有幾種 BDD 工具用於不同的平臺和程式語言。它們包括:
Cucumber(Ruby 框架)
SpecFlow(.NET 框架)
Behave(Python 框架)
JBehave(Java 框架)
JBehave Web(具有 Selenium 整合的 Java 框架)
Lettuce(Python 框架)
Concordion(Java 框架)
Behat(PHP 框架)
Kahlan(PHP 框架)
DaSpec(JavaScript 框架)
Jasmine(JavaScript 框架)
Cucumber-js(JavaScript 框架)
Squish GUI Tester(用於 JavaScript、Python、Perl、Ruby 和 Tcl 的 BDD GUI 測試工具)
Spock(Groovy 框架)
Yadda(對 Jasmine(JavaScript 框架)等框架提供 Gherkin 語言支援)
Cucumber
Cucumber 是一款用於可執行規範的免費工具,在全球範圍內使用。Cucumber 允許軟體開發團隊用純文字描述軟體的行為。文字以業務可讀的、特定於領域的語言編寫,並作為文件、自動化測試和開發輔助工具,全部整合到一種格式中。您可以使用超過 40 種不同的口語(英語、中文等)與 Cucumber 互動。
Cucumber – 主要功能
Cucumber 的主要功能如下:
Cucumber 可用於可執行規範、測試自動化和活文件。
Cucumber 可與 Ruby、Java、NET、Flex 或用任何語言編寫的 Web 應用程式配合使用。
Cucumber 支援更簡潔的表格測試——類似於 FIT 的功能。
Cucumber 透過將需求、自動化測試和文件融合到一個連貫的整體中徹底改變了軟體開發生命週期:可執行的純文字規範來驗證軟體。
SpecFlow
SpecFlow 是一個用於 .NET 平臺的 BDD 工具。SpecFlow 是一個開源專案。原始碼託管在 GitHub 上。
SpecFlow 使用 Gherkin 語法來描述特性。Gherkin 格式由 Cucumber 引入,也用於其他工具。Gherkin 語言作為一個專案在 GitHub 上維護 - https://github.com/cucumber/gherkin
Behave
Behave 用於 Python 框架。
Behave 使用三種類型的檔案,儲存在名為“features”的目錄中 -
包含行為場景的特性檔案。
“steps”目錄,包含場景的 Python 步驟實現。
可選地,一些環境控制(在步驟、場景、特性或整個流程之前和之後執行的程式碼)。
Behave 特性使用 Gherkin(帶有一些修改)編寫,並命名為“name.feature”。
附加到特性和場景的標籤可以透過傳遞給它們的“feature”或“scenario”物件在環境函式中獲得。在這些物件上,有一個名為“tags”的屬性,它是一個附加的標籤名稱列表,按照在特性檔案中找到的順序排列。
對 Gherkin 標準的修改 -
Behave 可以解析標準的 Gherkin 檔案,並擴充套件 Gherkin 以允許使用小寫步驟關鍵字,因為這些關鍵字有時可以使特性規範更易讀。
Lettuce
Lettuce 是一個基於 Cucumber 的非常簡單的 BDD 工具。它可以將純文字功能描述作為 Python 專案的自動化測試執行。Lettuce 旨在解決 BDD 中最常見的任務。
Concordion
Concordion 是一個用於 Java 框架的自動化示例規範的開源工具。
雖然核心功能很簡單,但強大的擴充套件框架 API允許您新增功能,例如使用 Excel 電子表格作為規範,向輸出新增螢幕截圖,顯示日誌資訊等。
Concordion 允許您使用段落、表格和正確的標點符號以普通語言編寫規範,並且不需要使用 Given/When/Then 結構化語言。
Concordion 已移植到其他語言,包括 -
C# (Concordion.NET)
Python (PyConcordion)
Ruby (Ruby-Concordion)
行為驅動開發 - Cucumber
Cucumber 是一個支援可執行規範、測試自動化和動態文件的工具。
行為驅動開發擴充套件了示例規範。它還規範了測試驅動開發的最佳實踐,特別是從外到內的視角。開發工作基於可執行規範。
可執行規範的主要特徵如下 -
可執行規範是 -
源自代表系統行為的示例。
由所有參與開發的人員(包括業務和利益相關者)共同編寫。
基於驗收標準。
基於可執行規範的驗收測試是自動化的。
使用共享的、無處不在的語言來編寫可執行規範和自動化測試,以便 -
在整個開發過程中使用特定領域的術語。
每個人,包括客戶和利益相關者,都以相同的方式討論系統、其需求和其實現。
在需求、設計文件、程式碼、測試等中使用相同的術語來討論系統。
任何人都可以閱讀和理解需求以及如何生成更多需求。
可以輕鬆地適應更改。
維護動態文件。
Cucumber 有助於此過程,因為它將可執行規範與系統的實際程式碼和自動化的驗收測試聯絡起來。
它實現此目的的方式實際上旨在讓客戶和開發人員協同工作。當驗收測試透過時,這意味著它所代表的系統行為規範已正確實現。
典型的 Cucumber 驗收測試
考慮以下示例。
特性 - 註冊
註冊應該快速且友好。
場景 - 成功註冊
新使用者應該收到一封確認電子郵件並獲得個性化的問候。
假設我選擇了註冊。
當我使用有效資訊註冊。
那麼我應該收到一封確認郵件。
並且我應該看到一條個性化的問候訊息。
從這個例子中,我們可以看到 -
驗收測試指的是特性。
特性由場景解釋。
場景由步驟組成。
規範以自然語言寫在純文字檔案中,但它是可執行的。
Cucumber 的工作原理
Cucumber 是一個命令列工具,它處理包含特性的文字檔案,查詢可以針對您的系統執行的場景。讓我們瞭解 Cucumber 的工作原理。
它利用了一些關於檔案如何命名以及它們位於何處的約定(各個資料夾),以便於入門。
Cucumber 允許您將規範、自動化測試和文件儲存在同一位置。
每個場景都是一系列步驟,描述了場景的前置條件、操作和後置條件;如果每個步驟都執行且沒有任何錯誤,則該場景將標記為透過。
在執行結束時,Cucumber 將報告有多少場景透過。
如果某些內容失敗,它將提供有關失敗內容的資訊,以便開發人員可以繼續進行。
在 Cucumber 中,特性、場景和步驟是用一種稱為Gherkin的語言編寫的。
Gherkin 是純文字英語(或 60 多種其他語言之一),具有一定的結構。Gherkin 容易學習,其結構允許您以簡潔的方式編寫示例。
Cucumber 執行包含用 Gherkin 編寫的可執行規範的檔案。
Cucumber 需要步驟定義將純文字 Gherkin 步驟轉換為將與系統互動的操作。
當 Cucumber 執行場景中的一個步驟時,它將查詢要執行的匹配步驟定義。
步驟定義是一小段程式碼,並附加了一個模式。
該模式用於將步驟定義連結到所有匹配的步驟,並且程式碼是 Cucumber 在看到 Gherkin 步驟時將執行的內容。
每個步驟都伴有一個步驟定義。
大多數步驟將收集輸入,然後委託給特定於您的應用程式領域的框架,以便對您的框架進行呼叫。
Cucumber 支援十多種不同的軟體平臺。您可以選擇適合您的 Cucumber 實現。每個 Cucumber 實現都提供相同的整體功能,並且它們也有自己的安裝過程和特定於平臺的功能。
對映步驟和步驟定義
Cucumber 的關鍵在於步驟和步驟定義之間的對映。

Cucumber 實現
以下是 Cucumber 的實現。
![]() |
Ruby/JRuby |
![]() |
JRuby(使用 Cucumber-JVM) |
![]() |
Java |
![]() |
Groovy |
![]() |
.NET(使用 SpecFlow) |
![]() |
JavaScript |
![]() |
JavaScript(使用 Cucumber-JVM 和 Rhino) |
![]() |
Clojure |
![]() |
Gosu |
![]() |
Lua |
![]() |
PHP(使用 Behat) |
![]() |
Jython |
![]() |
C++ |
![]() |
Tcl |
框架整合
以下是框架實現。
行為驅動開發 - Gherkin
Gherkin 是一種用於編寫特性、場景和步驟的語言。Gherkin 的目的是幫助我們編寫具體的需求。
要理解我們所說的具體需求是什麼,請考慮以下示例 -
應阻止客戶輸入無效的信用卡詳細資訊。
如果客戶輸入的信用卡號碼長度不正好為 16 位,當他們嘗試提交表單時,應重新顯示該表單,並顯示一條錯誤訊息,告知他們正確的位數。
後者沒有歧義,避免了錯誤,並且更易於測試。
Gherkin 旨在建立更具體的需求。在 Gherkin 中,上述示例如下所示 -
特性
輸入無效信用卡詳細資訊時的反饋 特性定義
在使用者測試中,我們看到許多人犯了錯誤 文件
背景適用於以下所有場景
假設我選擇了一件要購買的商品,
並且我即將輸入我的信用卡號碼
場景 - 信用卡號碼過短場景定義
當我輸入的卡號少於 16 位
並且所有其他詳細資訊都正確
並且我提交表單步驟
那麼應重新顯示錶單
並且我應該看到一條訊息,告知我正確的位數
Gherkin 格式和語法
Gherkin 檔案是純文字檔案,副檔名為 .feature。每行非空行都必須以 Gherkin 關鍵字開頭,後跟任意文字。關鍵字為 -
特性
場景
Given、When、Then、And、But(步驟)
背景
場景大綱
示例
"""(文件字串)
|(資料表)
@(標籤)
#(註釋)
*
特性
特性關鍵字用於描述軟體特性,以及對相關場景進行分組。特性有三個基本要素 -
關鍵字 – 特性。
特性的名稱,在與特性關鍵字相同的行上提供。
可選的(但強烈建議)描述,可以跨越多行,即包含特性關鍵字的行與以場景、背景或場景大綱開頭的行之間的所有文字。
除了名稱和描述之外,特性(Feature)還包含一系列場景或場景大綱,以及可選的背景。
通常情況下,.feature 檔案的命名方式是採用特性名稱,將其轉換為小寫,並用下劃線替換空格。例如:
feedback_when_entering_invalid_credit_card_details.feature
為了在您的系統中識別特性,您可以使用所謂的“特性注入模板”。
描述
Gherkin 文件的某些部分不必以關鍵字開頭。
在特性、場景、場景大綱或示例後面的行中,您可以編寫任何內容,只要沒有以關鍵字開頭即可。這就是包含描述的方式。
場景
為了表達您系統的行為,您需要為每個特性附加一個或多個場景。通常情況下,每個特性會有 5 到 20 個場景來完整地指定圍繞該特性的所有行為。
場景遵循以下模式:
描述初始上下文
描述一個事件
描述預期結果
我們從上下文開始,描述一個動作,並檢查結果。這透過步驟來完成。Gherkin 提供三個關鍵字來描述每個上下文、動作和結果作為步驟。
Given - 建立上下文
When - 執行動作
Then - 檢查結果
這些關鍵字提高了場景的可讀性。
示例
Scenario - 從賬戶中取款。
Given 我的賬戶中有 100 美元。
When 我請求取款 20 美元。
Then 應該發出 20 美元的鈔票。
如果在彼此下方有多個 Given 或 When 步驟,您可以使用 And 或 But。它們允許您詳細指定場景。
示例
Scenario - 使用被盜卡嘗試取款。
Given 我的賬戶中有 100 美元。
But 我的卡無效。
When 我請求取款 50 美元。
Then 我的卡不應該被退回。
And 我應該被告知聯絡銀行。
在建立場景時,請記住“每個場景都必須有意義,並且能夠獨立於任何其他場景執行”。這意味著:
您不能讓一個場景的成功條件取決於另一個場景之前是否執行過。
每個場景都會建立其特定的上下文,執行一項操作,並測試結果。
這樣的場景提供了以下好處:
測試將更簡單,更容易理解。
您可以只執行一部分場景,而無需擔心測試集被破壞。
根據您的系統,您可能能夠並行執行測試,從而減少執行所有測試所需的時間。
場景大綱
如果您必須編寫具有多個輸入或輸出的場景,您最終可能會建立多個僅值不同的場景。解決方案是使用場景大綱。要編寫場景大綱,
場景大綱步驟中的變數用 < 和 > 標記。
變數的各種值作為示例在表格中給出。
示例
假設您正在為計算器上的兩個數字相加編寫一個特性。
Feature - 加法。
Scenario Outline: Add two numbers. Given the input "<input>" When the calculator is run Then the output should be <output>" Examples | input | output | | 2+2 | 4 | | 98+1 | 99 | | 255+390 | 645 |
場景大綱部分之後總是跟著一個或多個示例部分,這些示例部分是表格的容器。該表格必須有一個標題行,對應於場景大綱步驟中的變數。下面的每一行都將建立一個新的場景,並填充變數值。
行為驅動開發 - SpecFlow
SpecFlow 是一個開源專案。原始碼託管在 GitHub 上。SpecFlow 用於儲存應用程式中特性(用例、使用者故事)驗收標準的特性檔案使用 Gherkin 語法定義。
Gherkin 格式由 Cucumber 引入,也由其他工具使用。Gherkin 語言作為 GitHub 上的一個專案維護 - https://github.com/cucumber/gherkin
特性元素和 SpecFlow
特性元素的關鍵特性是:
特性元素為特性檔案提供標題。特性元素包含應用程式中對應特性的名稱和高階描述。
SpecFlow 為特性元素生成一個單元測試類,類名派生自特性的名稱。
SpecFlow 從表示驗收標準的場景生成可執行的單元測試。
一個特性檔案可以包含多個場景,用於描述特性的驗收測試。
場景具有名稱,可以包含多個場景步驟。
SpecFlow 為每個場景生成一個單元測試方法,方法名派生自場景的名稱。
多個場景步驟
場景可以有多個場景步驟。有三種類型的步驟定義了先決條件、操作或驗證步驟,這些步驟構成了驗收測試。
不同的步驟型別分別以 Given、When 或 Then 關鍵字開頭,同一型別的後續步驟可以使用 And 和 But 關鍵字連結。
Gherkin 語法允許這三種步驟型別的任意組合,但場景通常具有 Given、When 和 Then 語句的不同塊。
場景步驟使用文字定義,並且可以具有名為 DataTable 的附加表格或名為 DocString 的多行文字引數。
場景步驟是執行任何自定義程式碼來自動化應用程式的主要方式。
SpecFlow 為每個場景步驟在單元測試方法中生成一個呼叫。該呼叫由 SpecFlow 執行時執行,該執行時將執行與場景步驟匹配的步驟定義。
匹配是在執行時完成的,因此即使尚未實現繫結,也可以編譯和執行生成的測試。
您可以在場景步驟中包含表格和多行引數。這些由步驟定義使用,並且作為附加的表格或字串引數傳遞。
標籤
標籤是可以分配給特性和場景的標記。將標籤分配給特性等同於將標籤分配給特性檔案中的所有場景。以 @ 開頭的標籤名稱表示標籤。
如果單元測試框架支援,SpecFlow 會從標籤生成類別。
生成的類別名稱與標籤名稱相同,但沒有前導 @。
您可以使用這些單元測試類別過濾和分組要執行的測試。例如,您可以將關鍵測試標記為 @important,然後更頻繁地執行這些測試。
背景元素
背景語言元素允許為特性檔案中的所有場景指定一個通用先決條件。
檔案的背景部分可以包含一個或多個場景步驟,這些步驟在任何其他場景步驟之前執行。
SpecFlow 從背景元素生成一個方法,該方法從為場景生成的所有單元測試中呼叫。
場景大綱
場景大綱可用於定義資料驅動的驗收測試。場景大綱始終由場景模板規範(使用 <佔位符> 語法的帶資料佔位符的場景)和一組提供佔位符值的示例組成。
如果單元測試框架支援,SpecFlow 會從場景大綱生成基於行的測試。
否則,它會為場景大綱生成一個引數化的單元測試邏輯方法,併為每個示例集生成一個單獨的單元測試方法。
為了獲得更好的可追溯性,生成的單元測試方法名稱派生自場景大綱標題和示例的第一個值(示例表格的第一列)。
因此,最好選擇一個唯一且描述性的引數作為示例集的第一列。
由於 Gherkin 語法確實要求所有示例列在場景大綱中具有匹配的佔位符,因此您甚至可以在示例集中引入任意列,用於以更具可讀性的方式命名測試。
SpecFlow 在匹配步驟繫結之前,將佔位符替換作為單獨的階段執行。
因此,步驟繫結中的實現和引數獨立於它們是透過直接場景還是場景大綱執行。
這允許您以後在驗收測試中指定更多示例,而無需更改步驟繫結。
註釋
您可以透過在行的開頭使用 # 在任何位置向特性檔案添加註釋行。但是請注意,規範中的註釋可能是驗收標準指定錯誤的標誌。SpecFlow 會忽略註釋行。