7 個實用的 pytest plugins
Posted on Apr 12, 2021 in Python 模組/套件推薦 by Amo Chen ‐ 3 min read
在 pytest 教學 一文,我們學會如何利用 pytest 更輕鬆地撰寫 Python 的測試程式,但 pytest 所提供的方便功能不僅僅如此,pytest 還有許多好用的 plugins 能夠利用,使用得當的話,將可增加開發效率。
剛好 15 amazing pytest plugins 中提到不少實用的 pytest plugins, 本文就將其中 7 項進行簡介。
本文環境
- Python 3.7
- pytest 6.2.3
- macOS 11.2
本文所提及之 plugins 皆可透過 pip
進行安裝。
報表類 Plugins
pytest-sugar
pytest 預設測試報表大概像以下形式:
$ pytest
=========================== test session starts ============================
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-0.x.y
cachedir: $PYTHON_PREFIX/.pytest_cache
rootdir: $REGENDOC_TMPDIR
collected 1 item
test_sample.py F [100%]
================================= FAILURES =================================
透過安裝 pytest-sugar 可以將報表進一步美化,例如下圖(引用自官方文件):
是否變得較為賞心悅目呢?
pytest-spec
如果喜歡在測試中寫上詳細的規格(spec/specification) 不妨參考 pytest-spec , 該 plugin 可以讓我們將 spec 作為測試函數的名字,或者將 spec 記錄於 docstring 中,並且在測試結果報表中列印出來,例如下圖(引用自官方文件):
不過,該 plugin 並沒有詳述如何啟用該 plugin, 如果要啟用該 plugin, 須在執行 pytest 時加上 --spec
參數,例如:
$ pytest --spec
如果想進一步設定 pytest-spec, 可以在 pytest.ini 檔案中新增 [tool:pytest]
區塊,例如以下範例:
[tool:pytest]
spec_header_format = {module_path}:
spec_test_format = {result} {docstring_summary}
spec_success_indicator = ✓
spec_failure_indicator = ✗
spec_skipped_indicator = s
spec_indent = " "
關於上述各項設定在此不多贅述,詳細請參考 官方文件 。
pytest-cov
測試時經常也會衡量覆蓋率,如果要在報表中顯示覆蓋率,可以安裝 pytest-cov 。
關於該 plugin 可以參考 Python pytest 整合 coverage 一文。
pytest-instafail
pytest 預設會在報表的最後才將失敗的測試報表一次列印出來,隨著測試越來越多,經常要等一段時間才能夠得到這些資訊。
為了解決上述困擾可以安裝 pytest-instafail ,並且於執行 pytest 時加上 --instafail
, 一旦測試失敗就會馬上看到失敗的報告:
$ pytest --instafail
平行化測試 Plugins
pytest-xdist
隨著測試案例越來越多,測試的執行勢必需要一段時間處理,不過仍可以透過平行化測試將測試以多個 processes 分散處理,或者將這些測試透過網路送至其他伺服器進行處理,以加速測試的進行。
要達成平行化測試的話,能夠安裝 pytest-xdist 解決,最簡單的方式即是加上 -n <NUMCPUS>
參數指定平行成 n 個 processes 進行測試,一般都會指定與 CPU 個數相同的數字,例如以下指令以 4 個 processes 進行平行測試:
$ pytest -n 4
成功的話,可以發現報表多了 1 行 gw0 [3] / gw1 [3] / gw2 [3] / gw3 [3]
,代表目前有 4 個 processes 在處理測試:
========================= test session starts ==========================
platform darwin -- Python 3.7.0, pytest-6.2.3, py-1.10.0, pluggy-0.13.1
rootdir: ..., configfile: pytest.ini
plugins: instafail-0.4.2, spec-3.1.0, xdist-2.2.1, forked-1.3.0
gw0 [3] / gw1 [3] / gw2 [3] / gw3 [3]
若要透過網路將測試送至其他伺服器進行處理,請詳閱 官方文件 。
時間相關 Plugins
pytest-freezegun
如果測試是需要固定住時間點,使得不管怎麼呼叫 datetime.now()
都是該時間點的話,可以使用 pytest-freezegun 。
該 plugin 提供 1 個 fixture 稱為 freezer
,透過該 fixture 可以隨意固定時間點,例如:
import pytest
from datetime import datetime
def test_moving_date(freezer):
now = datetime.now()
freezer.move_to('2012-12-12')
later = datetime.now()
assert now == later
上述範例執行之後會失敗,可以從報表中發現 datetime object 都已經被取代為 FakeDatetime
,而且在執行 freezer.move_to('2012-12-12')
之後,呼叫 datetime.now()
其時間已經被固定為 2012-12-12 00:00:00 ,也因此 2 個 datetime.now()
並不相等:
> assert now == later
E assert FakeDatetime(...3, 36, 675724) == FakeDatetime(... 12, 12, 0, 0)
E +FakeDatetime(2021, 4, 11, 16, 23, 36, 675724)
E -FakeDatetime(2012, 12, 12, 0, 0)
當然 freezer.move_to()
函式除了日期也支援時間,例如 freezer.move_to('2012-12-12 12:12:12')
,其他更多用法可參閱官方文件。
其他
pytest-picked
pytest-picked 可以只執行 git repo 中有更改的測試檔案,如此可以優先執行有變更的測試,以節省時間:
$ pytest --picked
官方文件有更詳細的用法,詳細可以至 pytest-picked 查看。
以上為 7 個實用的 pytest plugins 的介紹,如果想了解更多 pytest plugins 可參考 references 連結。
Happy Coding!
References
https://testandcode.com/116