在Python 語言中進行BDD的規格和測試文件的編寫的時候,常常會遇到下面的概念:
* Fixture : 測試設施。設定測試環境的預設狀態或值的機制。
* Background: 背景。所有場景的公共部分。
* Scenario: 場景。
* Given : 前置條件
* When: 用戶操作
* Then:預期結果
## 規格文件
pytest-bdd 和Behave 是Python中比較流行的BDD 框架,兩種使用的規格文件基本類型,規格文件都是以 .feature結尾,一個需求文件中只能有一個Feature字段,可以包含多個Scenario(用戶場景)。
Given->When->Then類似于準備->執行->驗證/清理的流程。
* Given:一般可以用來做預置條件/數據準備,下面第一個And也屬于Given。
* When下面的And都屬于When, 一般是操作步驟。
* Then: 一般用于驗證結果(斷言),也可以進行清理數據。
## Fixture 測試設施
在軟件測試中,"Fixture" 是一種設定測試環境的預設狀態或值的機制。通常為了某個測試或一組測試,需要一些預設的對象、文件或數據庫等等。如何設置和管理這些預設狀態就是 "Fixture" 的作用,它通常用來初始化測試環境,或者在每次測試完成后進行清理。
考慮到這個功能,有些中文翻譯可能會把 "Fixture" 翻譯為 **"固件"** 或 **"前置條件" **或 **"測試設施"**。然而,這通常還需要結合上下文具體理解。在很多開發文檔或技術討論中,也常常直接使用英文 "Fixture"。
在 BDD 和測試中,Fixture 是設置給定環境或編寫 "Given" 步驟所需的一項工作。可以把它看作是一個重復使用的預設條件,使你能夠用一致的環境運行測試。這些預設條件可能涉及各種各樣的事情,比如創建數據庫、初始化變量、創建類的實例,或者運行特定的命令等。
在 pytest,這些 fixtures 是用 @pytest.fixture 裝飾器聲明的 Python 函數。例如:
```
@pytest.fixture
def client():
from myapp import MyClient
return MyClient()
```
這個 client fixture 可以在測試函數、類或模塊中通過參數 re-use。
```
def test_get_data(client):
data = client.get_data()
assert data is not None
```
在 pytest-bdd 中,fixture 的使用方式非常相似,但支持為步驟 (given, when, then) 設置 fixture,使在 BDD 測試中更容易設置和共享上下文。
舉個例子:
```
from pytest_bdd import given, scenario, then, when
import pytest
@scenario('calculations.feature', 'Adding numbers')
def test_add():
pass
@pytest.fixture
def calc():
return Calculator()
@given('I have a calculator', target_fixture='calculator')
def i_have_a_calculator(calc):
return calc
@when('I add <number1> and <number2>')
def add_numbers(calculator, number1, number2):
calculator.add(int(number1), int(number2))
@then('I should get <result>')
def get_result(calculator, result):
assert calculator.result == int(result)
```
在這個例子中,
* @pytest.fixture 注解的 calc()方法創建了一個 Calculator 類的實例
* `@given('I have a calculator', target_fixture='calculator')` 的作用是 返回一個名為“calculator”的fixture(即測試用例執行前需要準備的對象或數據)。這個fixture可以在之后的測試步驟中被引用和使用。
使用這種方式的好處是在 BDD 的步驟中更容易地重用和共享設置和數據。同時,它也可以幫助你分離你的測試代碼,使得它們更加模塊化和易維護。
## Background 是什么?
在 BDD 中,`Background`關鍵字用于定義在執行每個場景時都需要執行的步驟。通常,這些步驟用于設置初始條件或預設環境。換句話說,它是需要在每個場景開始之前運行的給定(`Given`)步驟。
以下是一個例子,演示如何在 Background 中設置初始的環境狀態:
~~~
Feature: 乘坐地鐵
Background:
Given 我有一張有效的地鐵卡
Scenario: 乘坐地鐵
When 我刷地鐵卡
Then 旋轉門應該打開
Scenario: 余額不足
Given 我的卡余額是0
When 我刷地鐵卡
Then 旋轉門不會打開
~~~
在這個示例中,`Background`包含了一個 "Given 我有一張有效的地鐵卡" 的步驟。這意味著在執行每個場景 "乘坐地鐵" 和 "余額不足" 之前,測試始終會先執行這個步驟。
`Background`的目的是幫助減少測試場景之間的重復,并傳達對所有場景都有效的前提條件。但需要注意的是,過度使用`Background`可能會使測試復雜化和難以理解,特別是在`Background`中有很多步驟或它們的效果不明顯時。
## Fixture 和 Background 的區別
`Fixture`和`Background`都是在開啟測試前設置預期環境或狀態的工具,但它們在用途和功能上有所區別,用在不同的場景。
* **Fixture**:在 pytest 和許多其他測試框架中,fixture 是設置測試環境的一種工具,它為測試提供了需要的初識狀態或值。可以把 pytest fixture 理解為設置給定環境或預設需要的工作,它可以創建對象、連接數據庫、開啟服務器或其他任何為了測試需要預先設定的操作。Fixture 可以被多個測試用例重復使用,從而避免代碼的重復。
* **Background**:在 Gherkin 語言(被許多 BDD 框架,如 Cucumber 和 behave 使用)中,Background 是一個特殊的場景,它在包含它的`Feature`中的每個`Scenario`或`Scenario Outline`開始前運行。我們可以把 Background 理解成作為每個場景前提的共享步驟。**背景的目標是為了消除場景之間的冗余**。
它們的區別主要在于:
* Background 是 BDD 中 Gherkin 語法的一部分,用于描述在每個測試場景開始時的共享行為,
* 而 Fixture 是 pytest 測試中的一個概念,它更傾向于代碼層面,負責進行一些設置和清理工作。
Background 和Fixture 也可以一起使用。例如,在 Given 步驟中使用`fixture`去實現在`Background`中描述的行為。
```
Feature: 乘坐地鐵
Background:
Given 我有一張有效的地鐵卡
```
對應的`Given`實現可能如下:
```
@given("我有一張有效的地鐵卡", target_fixture="card")
def have_subway_card():
return SubwayCard(is_valid=True)
```
在這個例子中,`have_subway_card`就是一個 fixture,它在`Background`描述的`Given`步驟中被使用。
## Scenario 用戶場景
在行為驅動開發(Behavior-Driven Development,BDD)中,`Scenario`是描述一個特定功能如何在特定情境下工作的方法,或者說是描述功能如何被使用的故事。每個`Scenario`是一個完整的可測試的用戶故事。
`Scenario`通常使用 "Given-When-Then" 的格式描述,這種格式可以清晰地闡述環境條件、行為和期望結果。每個`Scenario`應該是自足并可以單獨運行。
以下是一個例子:
```
Scenario: User login with correct username and password
Given a user has been registered with username "user1" and password "pass1"
When the user login with username "user1" and password "pass1"
Then the login should be successful
```
在這個例子中:
* `Given`步驟設定了開始條件,即已經有一個注冊用戶 "user1",其密碼是 "pass1"。
* `When`步驟描述了用戶嘗試使用正確的用戶名和密碼登錄的行為。
* `Then`步驟描述了期望的結果,即登錄應該成功。
* 每個`Scenario`開始都是獨立的,不依賴于其他`Scenario`,每個`Scenario`均應清理其測試環境,以確保不會影響其他測試。這就是所謂的測試原子性。
* `Scenario`是 BDD 的核心部分,它幫助我們將抽象的需求轉化為具體、可執行和可驗證的測試。
*****
*****
- 前言
- 1.入門篇
- Python介紹
- 安裝與使用
- Python開發利器之VS Code
- 模塊安裝
- 命令行
- 一次Python無法安裝模塊的問題探索與解決之旅
- 命令運行
- Conda
- 下載地址
- 2.基礎篇
- 基礎語法
- 輸入與輸出
- with as的用法
- 注釋
- Python命令行參數
- 編碼
- 變量類型
- 列表遍歷
- 運算符
- 表達式語句
- 條件
- 循環
- 日期和時間
- 函數
- 高級語法
- @符號-裝飾器
- 模塊和包
- name
- init.py
- 錯誤和異常
- 面向對象
- 3.專題篇
- 常用功能
- Python 字符串連接
- python web
- Python CGI編程
- Python OAuth2
- 認證 Flask-HTTPAuth
- 常用命令
- 內置函數
- dir()
- print(f)
- 標準模塊
- sys
- pickle-數據序列化
- os
- IO(輸入輸出)
- 鍵盤輸入
- 文件讀寫
- 測試
- Python測試框架之pytest快速入門
- pytest-bdd快速示例和問題解決
- 基于pytest-bdd的項目目錄結構和命名規范
- python BDD 的相關概念
- Behave介紹和快速示例
- Python BDD之Behave測試報告
- Python BDD 框架比較之 pytest-bdd vs behave
- pytest進階
- Flask + pytest測試
- 參考網址
- pytest-bdd進階
- hehave進階
- 測試路徑
- python + selunium
- HTML 根據多層CSS 查找元素
- 等待執行
- 使用text 查找 span
- pytest如何在控制臺輸出
- 4.問題篇
- pip pip3 及區別
- TypeError: can only concatenate str (not "NoneType") to str
- 5.實戰篇
- matplotlib-繪圖包
- 導入類
- 命名規范
- 模塊查找
- 6.進階篇
- Flask
- Flask介紹
- Flask擴展模塊
- Flask-Login
- 問題
- Jinja2
- Flask-RESTful
- Flask-JWT-Extended
- WSGI
- Flask-SQLAlchemy
- 部署
- Flask VS Django
- Flask Web
- Flask + Vue
- Flask實戰
- Flask 標準目錄結構
- Blueprints
- 參考
- FastAPI 測試
- https 證書 Caused by SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate