簡介
以下定義適用於本章。
- 腳本
包含 Python 代碼的單個文件,旨在直接從 Python 中運行,例如 python my_script.py。
- 可導入的腳本
導入時不執行代碼的腳本。代碼只有在直接運行時纔會被執行。
- 應用程序
指的是在 requirements.txt 文件中定義了外部依賴的軟件包或腳本。Cards 項目也是一個應用程序,但它是用 pip 安裝的。Cards的外部依賴在其pyproject.toml文件中定義,並在pip安裝時被拉入。在這一章中,我們將特別關注那些不能或選擇不使用pip的應用程序。
我們將從測試一個腳本開始。然後我們將修改該腳本,以便我們可以導入它進行測試。然後,我們將添加一個外部依賴,並看看測試應用程序。
在測試腳本和應用程序時,經常會出現一些問題。
- 如何從測試中運行一個腳本?
- 如何從腳本中捕獲輸出?
- 把源模塊或包導入我的測試中。如果測試和代碼在不同的目錄下,我如何使之工作?
- 如果沒有包可以構建,我如何使用 tox?
- 如何讓Tox從requirements.txt文件中引入外部依賴?
測試簡單的Python腳本
讓我們從經典的編碼例子開始,Hello World!。
ch12/script/hello.py
print("Hello, World!")
對於hello.py腳本,我們面臨的挑戰是:(1)如何從測試中運行它,以及(2)如何捕獲輸出。作爲 Python 標準庫的一部分,subprocess 模塊 有一個 run() 方法,可以很好地解決這兩個問題。
ch12/script/test_hello.py
print("Hello, World!")
執行
$ pytest -v test_hello.py
============================= test session starts =============================
platform win32 -- Python 3.9.13, pytest-7.1.2, pluggy-1.0.0 -- D:\ProgramData\Anaconda3\python.exe
cachedir: .pytest_cache
rootdir: D:\code\pytest_quick\ch12\script, configfile: tox.ini
plugins: allure-pytest-2.12.0, Faker-4.18.0, tep-0.8.2, anyio-3.5.0, cov-4.0.0
collecting ... collected 1 item
test_hello.py::test_hello PASSED [100%]
============================== 1 passed in 0.13s ==============================
用subprocess.run()測試小的腳本效果還可以,但它確實有缺點。我們可能想分別測試較大的腳本的各個部分。這是不可能的,除非我們把功能分成幾個函數。
測試可導入的Python腳本
ch12/script_importable/hello.py
def main():
print("Hello, World!")
if __name__ == "__main__":
main()
ch12/script_importable/test_hello.py
import hello
def test_main(capsys):
hello.main()
output = capsys.readouterr().out
assert output == "Hello, World!\n"
參考資料
- 本文涉及的python測試開發庫 謝謝點贊!
- 本文相關海量書籍下載
分離代碼和測試代碼
script_src
├── src
│ └── hello.py
├── tests
│ └── test_hello.py
└── pytest.ini
需要把我們要導入的源代碼的目錄添加到 sys.path 中。pytest 有選項可以幫助我們,即 pythonpath。該選項是爲pytest 7引入的。如果你需要使用pytest 6.2,你可以使用pytest-srcpaths插件,在pytest 6.2.x中加入這個選項。
首先我們需要修改我們的pytest.ini,將pythonpath設置爲src。
ch12/script_src/pytest.ini
[pytest]
addopts = -ra
testpaths = tests
pythonpath = src