良好的整合實務¶
使用 pip 安裝套件¶
對於開發,我們建議您使用 venv
進行虛擬環境設定,並使用 pip 安裝您的應用程式和任何依賴項,以及 pytest
套件本身。這確保您的程式碼和依賴項與您的系統 Python 安裝隔離。
在您的儲存庫根目錄中建立一個 pyproject.toml
檔案,如 Packaging Python Projects 中所述。前幾行應如下所示
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[project]
name = "PACKAGENAME"
version = "PACKAGEVERSION"
其中 PACKAGENAME
和 PACKAGEVERSION
分別是您的套件的名稱和版本。
然後,您可以從同一個目錄執行以下命令,以「可編輯」模式安裝您的套件
pip install -e .
這讓您可以隨意更改您的原始程式碼(包括測試和應用程式)並重新運行測試。
Python 測試探索的慣例¶
pytest
實作了以下標準測試探索
如果未指定任何參數,則從
testpaths
(如果已配置)或當前目錄開始收集。或者,可以使用目錄、檔案名稱或節點 ID 的任意組合的命令行參數。遞迴進入目錄,除非它們與
norecursedirs
相符。在這些目錄中,搜尋
test_*.py
或*_test.py
檔案,並通過它們的 測試套件名稱 導入。從這些檔案中,收集測試項目
類別外部以
test
為前綴的測試函數或方法。在以
Test
為前綴的測試類別(沒有__init__
方法)內部,以test
為前綴的測試函數或方法。以@staticmethod
和@classmethods
修飾的方法也被考慮在內。
有關如何自訂測試探索的範例,請參閱 變更標準 (Python) 測試發現。
在 Python 模組中,pytest
也使用標準的 unittest.TestCase 子類化技術來探索測試。
選擇測試佈局¶
pytest
支援兩種常見的測試佈局
應用程式程式碼外的測試¶
如果您有很多功能測試,或者由於其他原因想要將測試與實際應用程式程式碼分開(通常是個好主意),則將測試放入實際應用程式程式碼之外的額外目錄中可能很有用
pyproject.toml
src/
mypkg/
__init__.py
app.py
view.py
tests/
test_app.py
test_view.py
...
這具有以下優點
您的測試可以在執行
pip install .
後針對已安裝的版本運行。您的測試可以在執行
pip install --editable .
後針對具有可編輯安裝的本地副本運行。
對於新專案,我們建議使用 importlib
導入模式(請參閱 which-import-mode 以獲得詳細說明)。為此,請將以下內容添加到您的 pyproject.toml
中
[tool.pytest.ini_options]
addopts = [
"--import-mode=importlib",
]
通常,但特別是如果您使用預設導入模式 prepend
,強烈建議使用 src
佈局。在這裡,您的應用程式根套件位於您根目錄的子目錄中,即 src/mypkg/
而不是 mypkg
。
這種佈局可以防止許多常見的陷阱,並且有很多好處,這些好處在 Ionel Cristian Mărieș 的這篇出色的 部落格文章 中得到了更好的解釋。
注意
如果您不使用可編輯安裝並且使用上面的 src
佈局,則需要擴展 Python 的模組檔案搜尋路徑,以便直接針對本地副本執行測試。您可以通過設定 PYTHONPATH
環境變數以特別的方式執行此操作
PYTHONPATH=src pytest
或以永久方式使用 pythonpath
配置變數,並將以下內容添加到您的 pyproject.toml
中
[tool.pytest.ini_options]
pythonpath = "src"
注意
如果您不使用可編輯安裝並且不使用 src
佈局(mypkg
直接在根目錄中),您可以依靠 Python 預設將當前目錄放入 sys.path
中的事實來導入您的套件並運行 python -m pytest
以直接針對本地副本執行測試。
有關調用 pytest
和 python -m pytest
之間的差異的更多信息,請參閱 調用 pytest 與 python -m pytest。
作為應用程式程式碼一部分的測試¶
如果您在測試和應用程式模組之間有直接關係,並且想要將它們與您的應用程式一起分發,則將測試目錄內聯到您的應用程式套件中會很有用
pyproject.toml
[src/]mypkg/
__init__.py
app.py
view.py
tests/
__init__.py
test_app.py
test_view.py
...
在這個方案中,可以使用 --pyargs
選項輕鬆運行您的測試
pytest --pyargs mypkg
pytest
將發現 mypkg
的安裝位置,並從那裡收集測試。
請注意,這種佈局也適用於上一節中提到的 src
佈局。
注意
您可以為您的應用程式使用命名空間套件 (PEP420),但 pytest 仍將根據 __init__.py
檔案的存在執行 測試套件名稱 探索。如果您使用上面兩種建議的檔案系統佈局之一,但從您的目錄中省略 __init__.py
檔案,它應該可以正常工作。但是,從「內聯測試」中,您將需要使用絕對導入來訪問您的應用程式程式碼。
注意
在 prepend
和 append
導入模式下,如果 pytest 在遞迴到檔案系統時找到 "a/b/test_module.py"
測試檔案,它將按如下方式確定導入名稱
確定
basedir
:這是第一個「向上」(朝向根目錄)不包含__init__.py
的目錄。例如,如果a
和b
都包含__init__.py
檔案,則a
的父目錄將成為basedir
。執行
sys.path.insert(0, basedir)
以使測試模組可以在完全限定的導入名稱下導入。import a.b.test_module
,其中路徑由將路徑分隔符/
轉換為「.」字元確定。這意味著您必須遵循目錄和檔案名稱直接映射到導入名稱的慣例。
這種稍微演變的導入技術的原因是,在較大的專案中,多個測試模組可能會相互導入,因此導出規範的導入名稱有助於避免意外情況,例如測試模組被導入兩次。
使用 --import-mode=importlib
,事情變得不那麼複雜,因為 pytest 不需要更改 sys.path
,這使得事情變得不那麼令人意外。
選擇導入模式¶
由於歷史原因,pytest 預設為 prepend
導入模式,而不是我們為新專案推薦的 importlib
導入模式。原因在於 prepend
模式的工作方式
由於沒有套件可以從中導出完整的套件名稱,pytest
會將您的測試檔案作為頂層模組導入。第一個範例(src 佈局)中的測試檔案將通過將 tests/
添加到 sys.path
中,作為頂層模組 test_app
和 test_view
導入。
與導入模式 importlib
相比,這會導致一個缺點:您的測試檔案必須具有唯一的名稱。
如果您需要具有相同名稱的測試模組,作為一種解決方法,您可以將 __init__.py
檔案添加到您的 tests
資料夾和子資料夾中,將它們更改為套件
pyproject.toml
mypkg/
...
tests/
__init__.py
foo/
__init__.py
test_view.py
bar/
__init__.py
test_view.py
現在 pytest 將模組作為 tests.foo.test_view
和 tests.bar.test_view
加載,允許您擁有相同名稱的模組。但是現在這引入了一個微妙的問題:為了從 tests
目錄加載測試模組,pytest 將儲存庫的根目錄前置到 sys.path
,這增加了現在 mypkg
也可以導入的副作用。
如果您使用像 tox 這樣的工具在虛擬環境中測試您的套件,這會很成問題,因為您想要測試您的套件的已安裝版本,而不是儲存庫中的本地程式碼。
importlib
導入模式沒有上述任何缺點,因為導入測試模組時不會更改 sys.path
。
tox¶
完成工作並想要確保您的實際套件通過所有測試後,您可能需要研究虛擬環境測試自動化工具 tox。tox
幫助您設定具有預定義依賴項的 virtualenv 環境,然後使用選項執行預先配置的測試命令。它將針對已安裝的套件而不是針對您的原始程式碼簽出運行測試,從而幫助檢測套件問題。
不要通過 setuptools 運行¶
不建議與 setuptools 集成,即您不應使用 python setup.py test
或 pytest-runner
,並且將來可能會停止工作。
由於它依賴於 setuptools 的已棄用功能,並且依賴於破壞 pip 中安全機制的功能,因此不建議使用此方法。例如,'setup_requires' 和 'tests_require' 會繞過 pip --require-hashes
。有關更多資訊和遷移說明,請參閱 pytest-runner 通知。另請參閱 pypa/setuptools#1684。
setuptools 打算 移除 test 命令。
使用 flake8-pytest-style 檢查¶
為了確保在您的專案中正確使用 pytest,使用 flake8-pytest-style flake8 插件可能會有所幫助。
flake8-pytest-style 檢查 pytest 程式碼中的常見錯誤和編碼風格違規,例如 fixture 的不正確使用、測試函數名稱和標記。通過使用此插件,您可以在開發過程的早期捕獲這些錯誤,並確保您的 pytest 程式碼一致且易於維護。
可以在 flake8-pytest-style 的 PyPI 頁面 上找到 flake8-pytest-style 檢測到的 lint 列表。
注意
flake8-pytest-style 不是官方的 pytest 專案。某些規則強制執行某些風格選擇,例如使用 @pytest.fixture()
而不是 @pytest.fixture
,但您可以配置插件以適合您偏好的風格。