從pytest原始碼的角度分析pytest工作原理
從 pytest
原始碼的角度來分析其工作原理,我們需要關注幾個關鍵的部分,特別是 pytest
的啟動過程以及測試的收集與執行。下面是基於 pytest
原始碼的一個高層次的概述。
pytest 的啟動過程
-
命令列解析:
pytest
的入口點是conftest.py
檔案中的pytest.main()
函式。- 在這個函式中,首先透過
pytest.config.get_config()
獲取配置。 - 接著使用
pytest.config.parse()
來解析命令列引數。
-
配置載入:
pytest
會在當前目錄及其父目錄遞迴地查詢配置檔案,比如pytest.ini
或pyproject.toml
。- 使用
pytest.config.Config
類來儲存配置資訊。
-
外掛管理:
- 透過
pytest.hookspec
和pytest.pluginmanager
來管理外掛。 - 外掛可以在各個階段被註冊並呼叫。
- 透過
測試收集過程
-
收集器初始化:
pytest
使用pytest.collect
模組來處理測試收集。Session.from_parent
方法建立一個新的Session
例項。Collector.from_parent
方法用於構建收集器樹。
-
測試檔案發現:
pytest
透過Session.perform_collect
方法來遍歷目錄結構並發現測試模組。File.from_parent
方法用於建立File
例項來代表測試檔案。Function.from_parent
方法用於建立Function
例項來代表測試函式。
-
測試項構建:
- 一旦發現了測試檔案,就會透過
collect
方法來收集檔案中的測試函式。 - 測試函式會被轉換成
Item
例項。
- 一旦發現了測試檔案,就會透過
測試執行過程
-
測試項準備:
- 在測試開始之前,會呼叫
Session.perform_setup
方法來進行一些預處理。 - 這個階段可能包括設定環境變數、初始化資料庫連線等。
- 在測試開始之前,會呼叫
-
測試項執行:
Session.runtestloop
方法控制測試項的實際執行。- 對於每一個
Item
例項,都會呼叫Session.perform_test
方法來執行測試。
-
測試結果收集:
- 測試執行的結果會被收集並儲存在
Item
例項中。 - 可能會觸發
pytest_runtest_logreport
hook,該 hook 被用來處理測試報告。
- 測試執行的結果會被收集並儲存在
-
異常處理:
- 如果測試過程中發生異常,
pytest
會捕獲這些異常並記錄下來。 - 異常可以透過
pytest_runtest_makereport
hook 來處理。
- 如果測試過程中發生異常,
測試報告生成
Session
例項負責收集所有的測試結果。Session.exitstatus
屬性會根據測試結果來確定程式的退出狀態碼。pytest
可以生成多種格式的報告,這取決於安裝的外掛。
示例程式碼片段
下面是一些示例程式碼片段,展示了 pytest
原始碼中的關鍵部分:
# pytest/conftest.py def main(args=None): # 解析命令列引數 config = get_config(args) # 載入外掛 pm = PluginManager() pm.load_setuptools_entrypoints('pytest11') # 建立 Session 例項 session = Session.from_parent(config, plugins=pm) # 執行測試 session.runtestloop() # 返回退出狀態 return session.exitstatus # pytest/collect.py def perform_collect(session, collector): # 收集測試檔案和測試函式 items = [] for item in collector.collect(): items.append(item) return items # pytest/runner.py def runtest_protocol(item, nextitem): # 執行測試項 report = item.runtest() if report is None: # 處理異常情況 report = item.makereport() # 處理測試報告 item.session._hookmanager.hook.pytest_runtest_logreport(report=report)