pytest是一種流行的Python測試框架,支持創建簡單的單元測試,也支持創建復雜的功能和集成測試。它提供了一系列有用的功能,能夠方便地編寫,組織和運行測試用例,并生成豐富的測試報告。
pytest的主要特點包括:
* 自動發現測試用例:pytest會自動查找項目中以test_或者以_test結尾的函數或類,并執行它們。
* 參數化測試:pytest允許使用@pytest.mark.parametrize標記來指定多組輸入參數和預期輸出值,以簡化測試用例的編寫和管理。
* 豐富的斷言方式:pytest支持多種斷言方法,如assert語句、pytest.assert函數、pytest-assume插件以及第三方斷言庫等,可以讓開發人員更輕松地編寫和維護測試用例。
* 插件化架構:pytest允許通過插件來擴展其功能,它有很多官方和社區提供的插件,可以幫助開發人員處理日志、代碼覆蓋率、性能測試等各種任務。
* 可與`unittest`和`nose`無縫對接
* 豐富的測試報告:pytest會自動生成豐富的測試報告,包括測試用例的執行情況、失敗原因、覆蓋狀態等信息,并支持多種輸出格式,如HTML,JUnit XML等。
使用pytest編寫和運行測試用例相對于其他測試框架來說更加簡潔和靈活,同時它也是Python社區中廣泛使用的測試工具之一。
## 使用標準庫unittest進行單元測試
介紹pytest之前, 先來看一下Python內置的測試庫unittest, unittest是Python 標準庫的一部分,在安裝完Python之后就可以使用, 不需要安裝任何其他模塊。
Python unittest是Python自帶的一個單元測試框架,用于編寫和運行測試用例,以確保代碼的正確性和可靠性。unittest提供了一系列的工具和斷言方法,使得編寫測試用例變得更加簡單和高效。通過使用unittest,開發人員可以快速運行測試用例并自動化測試過程,從而節省時間和人力成本。
在Python中,unittest常被用作測試框架,它不僅僅用于單元測試,還可以進行集成測試和功能測試。unittest框架提供了豐富的API、測試控制器以及測試加載器,使得測試用例的編寫和執行變得更容易。
使用unittest編寫測試用例的流程如下:
1. 創建一個測試類,繼承unittest.TestCase類。
2. 在測試類中編寫測試方法。測試方法必須以test\_開頭,用于測試代碼的特定功能。
3. 在測試方法中使用斷言方法(如assertEqual、assertTrue等)判斷代碼的執行結果是否符合預期。
4. 運行測試用例,并查看測試報告,根據測試結果進行代碼調整和優化。
直接上代碼示例:
```python
import unittest
def add(a, b):
return a + b
class TestAdd(unittest.TestCase):
def test_add(self):
self.assertEqual(add(1, 2), 3)
if __name__ == '__main__':
unittest.main()
```
一個測試用例是一個完整的單元測試流程,包括測試前的準備環節、執行測試動作的環節、與期望結果的對比的環節。在`unittest`中,測試用例是通過繼承`unittest.TestCase`類來實現的,這個示例中定義了一個名為 `add` 的函數,并且使用了 Python 的 unittest 模塊對這個函數進行了測試。
* `TestAdd` 類繼承自 `unittest.TestCase` 類,并包含了一個名為 `test_add` 的測試方法。
* 在這個方法中,使用 `self.assertEqual` 方法來檢查 `add` 函數是否正確計算了加法。最后,使用 `unittest.main()` 運行測試。
運行成功的界面如下:

如果運行失敗是怎么顯示的呢? 修改上面的 ` self.assertEqual(add(1, 2), 3)` => ` self.assertEqual(add(1, 2), 4)` 讓測試失敗, 失敗的界面如下:

## 安裝 pytest
如果沒有安裝`pytest`,可以使用`pip`來安裝:
```
pip install pytest
```
如果不確定有沒有安裝`pytest`, 可以使用 `pip list` 查看安裝的模塊, 比如:

pytest 安裝成功的界面如下:

## 使用 pytest 編寫單元測試
`pytest`工具會自動找到文件名和函數名都以`test`開頭的測試用例。
這里定義一個加法函數并對這個函數進行測試, 首先創建一個名為`test_sample.py`的文件,內容如下:
```python
def add(a, b):
return a + b
def test_add():
assert add(1, 2) == 3
```
## 運行pytest 測試
命令行切換到包含`test_sample.py`的目錄,運行`pytest`命令,`pytest`會運行所有發現的測試,并產生一個測試報告,運行的效果如下圖“

測試失敗情況下,pytest 怎么顯示呢?`pytest`會詳細地顯示哪個測試失敗,以及失敗的詳細原因。這里故意定義一個執行錯誤的函數test_add2(), 代碼如下:
```python
def add(a, b):
return a + b
def test_add():
assert add(1, 2) == 3
def test_add2():
assert add(1, 2) == 4
```
執行后的效果如下圖:

除了在命令行控制臺運行和查看pytest的結果外, 也可以在VS Code 的Testing的活動欄,運行和查看結果。效果如下圖:

需要注意的是: 點擊Testing的活動欄之后, 需要選擇測試的框架為 pytest。
## 使用pytest 運行功能測試
`pytest`是一個非常靈活強大的 Python 測試框架,它既能進行單元測試,也能進行功能測試, 通常與 Flask(輕量級的 Python web 框架)一起使用。
Flask 模塊需要先安裝, 安裝方式是 `pip install flask`, 安裝完成之后就可以編寫Flask代碼了,
這里定義一個 Flask Web 應用,并且需要測試當訪問`/hello`時是否能返回 "Hello, World!", 代碼如下:
```
from flask import Flask
def create_app():
app = Flask(__name__)
@app.route('/hello')
def hello():
return 'Hello, World!'
return app
if __name__ == '__main__':
app = create_app()
app.run()
```
運行之后通過瀏覽器訪問的效果如下圖:

接下來, 使用`pytest`來進行功能測試,使用Flask的測試客戶端來模擬訪問, 定義測試的文件test_app.py , 內容如下:
```
import pytest
from app import create_app
@pytest.fixture
def client():
app = create_app()
app.config['TESTING'] = True
with app.test_client() as client:
yield client
def test_hello(client):
response = client.get('/hello')
assert response.data == b'Hello, World!'
```
* 使用 @pytest.fixture 裝飾器定義了一個名為 client 的測試夾具。該夾具在測試過程中可以作為參數傳遞給測試函數。在這個夾具函數中,創建了一個測試用的 Flask 應用,并將其配置為測試模式。
* `with`語句創建了一個上下文環境,以確保客戶端在每次測試運行前都被正確地初始化并且在測試完成后被清理掉。
* `yield`語句使客戶端對象在測試用例中可用,例如向應用程序發出 HTTP 請求。
* `test_client()`方法是 Flask 測試客戶端的簡單實現。它可以模擬客戶端發送 HTTP 請求,并對響應進行驗證。
使用`test_client()`方法可以快速編寫 Flask 應用程序的單元測試,而無需啟動真實的服務器或處理實際的網絡通信。在測試中,你可以發送請求并檢查響應,以確保應用程序按預期工作。
* 定義了一個名為 test_hello 的測試函數,并將上述夾具 client 作為參數傳遞進去。在測試函數中,使用 client.get('/hello') 發起了一個 GET 請求,并檢查返回值是否等于 b'Hello, World!'。如果返回值和預期值不一致,那么測試將會失敗。
* 在 Python 中,當字符串前面帶有前綴`b`時,表示這是一個 bytes 類型的字符串,而不是普通的 str 類型。bytes 類型的字符串在 Python 中是一種原生的二進制序列類型,它的每個字符都是一個字節,可以存儲任意的二進制數據。
在 Flask 應用中,當使用`response.data`獲取 HTTP 響應的內容時,返回的是 bytes 類型的內容,因為 HTTP 響應的內容是以二進制字節流的形式傳輸的。因此,在進行 HTTP 響應內容的比較時,需要使用 bytes 類型的字符串,而不是普通的 str 類型字符串。
運行測試的效果如下圖:

## 參考
* pytest官方站點: [https://docs.pytest.org/en/7.4.x/](https://docs.pytest.org/en/7.4.x/)
*****
*****
- 前言
- 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