1. 通過python -m pytest
調(diào)用pytest
你可以通過python的解釋器來執(zhí)行測試:
python -m pytest [...]
但是,這和直接執(zhí)行pytest [...]
命令的效果幾乎是一模一樣的喊括;
2. pytest
執(zhí)行結(jié)束時返回的狀態(tài)碼
pytest
命令執(zhí)行結(jié)束胧瓜,可能會返回以下六種狀態(tài)碼:
- 0:(OK)所有收集到的用例測試通過
- 1:(TESTS_FAILED)有用例測試失敗
- 2:(INTERRUPTED)用戶打斷測試執(zhí)行
- 3:(INTERNAL_ERROR)測試執(zhí)行的過程中,發(fā)生內(nèi)部錯誤
- 4:(USAGE_ERROR)
pytest
命令使用錯誤 - 5:(NO_TESTS_COLLECTED)沒有收集到測試用例
它們在枚舉類 _pytest.main.ExitCode 中聲明郑什。并且府喳,其作為公開API的一部分,能夠直接引入和訪問:
from pytest import ExitCode
3. 獲取幫助信息
pytest --version # 查看版本號和pytest的引入路徑
pytest -h # 查看幫助信息
4. 最多允許失敗的測試用例數(shù)
當(dāng)達(dá)到最大上限時蘑拯,退出執(zhí)行劫拢;如未配置,則沒有上限:
pytest -x # 遇到第一個失敗時强胰,退出執(zhí)行
pytest --maxfail==2 # 遇到第二個失敗時,退出執(zhí)行
5. 執(zhí)行指定的測試用例
pytest
支持多種方式來執(zhí)行特定的測試用例:
5.1. 執(zhí)行指定模塊中的測試用例
pytest test_mod.py
5.2. 執(zhí)行指定目錄下所有的測試用例
pytest testing/
5.3. 執(zhí)行文件名妹沙、類名或者函數(shù)名中包含特定關(guān)鍵字的測試用例
執(zhí)行當(dāng)前目錄下偶洋,名字包含_class
但不包含two
的測試用例:
pytest -k "_class and not two" .
注意:python的關(guān)鍵字不可以應(yīng)用在
-k
選項中,例如距糖,class
玄窝、def
等。
5.4. 執(zhí)行指定nodeid
的測試用例
pytest
為每一個收集到的測試用例指定一個唯一的nodeid
悍引。其由模塊名加說明符構(gòu)成恩脂,中間以::
間隔。
其中趣斤,說明符可以是類名俩块、函數(shù)名以及由parametrize
標(biāo)記賦予的參數(shù):
# src/chapter-2/test_nodeid.py
import pytest
def test_one():
print('test_one')
assert 1
class TestNodeId:
def test_one(self):
print('TestNodeId::test_one')
assert 1
@pytest.mark.parametrize('x,y', [(1, 1), (3, 4)])
def test_two(self, x, y):
print(f'TestNodeId::test_two::{x} == {y}')
assert x == y
在上述示例中,我們創(chuàng)建了三個測試用例浓领,分別對應(yīng)不同的說明符:
-
指定函數(shù)名執(zhí)行
$ pipenv run pytest -q -s src/chapter-2/test_nodeid.py::test_one test_one . 1 passed in 0.01s
-
指定類名+函數(shù)名執(zhí)行
$ pipenv run pytest -q -s src/chapter-2/test_nodeid.py::TestNodeId::test_one TestNodeId::test_one . 1 passed in 0.01s
-
指定由
parametrize
標(biāo)記賦予的參數(shù)執(zhí)行$ pipenv run pytest -q -s src/chapter-2/test_nodeid.py::TestNodeId::test_two[1-1] TestNodeId::test_two::1 == 1 . 1 passed in 0.01s
這里對參數(shù)
x
玉凯、y
賦值的形式是[1-1]
,中間以-
間隔联贩;單個或多個參數(shù)的賦值形式以此類比漫仆;并且,只能為
[1-1]
或者[3-4]
泪幌,其它的會報錯盲厌;
5.5. 執(zhí)行指定標(biāo)記的用例
pytest -m slow
5.6. 執(zhí)行指定包中的測試用例
pytest --pyargs pkg.testing
pytest
會引入pkg.testing
包,并在它的系統(tǒng)目錄下搜尋測試用例并執(zhí)行祸泪;
6. 修改回溯信息的輸出模式
pytest回溯信息的輸出一共有六種模式:auto/long/short/line/native/no吗浩,用--tb
選項指定:
pytest -l, --showlocals # 打印本地變量
pytest --tb=auto # 默認(rèn)模式
pytest --tb=long # 盡可能詳細(xì)的輸出
pytest --tb=short # 更簡短的輸出
pytest --tb=line # 每個失敗信息總結(jié)在一行中
pytest --tb=native # python的標(biāo)準(zhǔn)輸出
pytest --tb=no # 不打印失敗信息
--full-trace
是一種比--tb=long
更詳細(xì)的輸出模式。它甚至能觀察到用戶打斷執(zhí)行(Ctrl+C
)時的回溯信息浴滴,而上述六種模式默認(rèn)是不輸出此類信息的拓萌。
7. 總結(jié)報告
-r
選項可以在執(zhí)行結(jié)束后,打印一個簡短的總結(jié)報告升略。在執(zhí)行的測試用例很多時微王,可以讓你對結(jié)果有個清晰的了解:
# src/chapter-2/test_report.py
import pytest
@pytest.fixture
def error_fixture():
assert 0
def test_ok():
print("ok")
def test_fail():
assert 0
def test_error(error_fixture):
pass
def test_skip():
pytest.skip("skipping this test")
def test_xfail():
pytest.xfail("xfailing this test")
@pytest.mark.xfail(reason="always xfail")
def test_xpass():
pass
$ pipenv run pytest -q -rA src/chapter-2/test_report.py
.FEsxX [100%]
================================ ERRORS =================================
_____________________ ERROR at setup of test_error ______________________
@pytest.fixture
def error_fixture():
> assert 0
E assert 0
src/chapter-2/test_report.py:27: AssertionError
=============================== FAILURES ================================
_______________________________ test_fail _______________________________
def test_fail():
> assert 0
E assert 0
src/chapter-2/test_report.py:35: AssertionError
================================ PASSES =================================
________________________________ test_ok ________________________________
------------------------- Captured stdout call --------------------------
ok
======================== short test summary info ========================
PASSED src/chapter-2/test_report.py::test_ok
SKIPPED [1] /Users/yaomeng/Private/Projects/pytest-chinese-doc/src/chapter-2/test_report.py:44: skipping this test
XFAIL src/chapter-2/test_report.py::test_xfail
reason: xfailing this test
XPASS src/chapter-2/test_report.py::test_xpass always xfail
ERROR src/chapter-2/test_report.py::test_error - assert 0
FAILED src/chapter-2/test_report.py::test_fail - assert 0
1 failed, 1 passed, 1 skipped, 1 xfailed, 1 xpassed, 1 error in 0.08s
-r
選項后面要緊接這一個參數(shù)屡限,用于過濾顯示測試用例的結(jié)果。
以下是所有有效的字符參數(shù):
- f:失敗的
- E:出錯的
- s:跳過執(zhí)行的
- x:跳過執(zhí)行炕倘,并標(biāo)記為xfailed的
- X:跳過執(zhí)行钧大,并標(biāo)記為xpassed的
- p:測試通過的
- P:測試通過,并且有輸出信息的罩旋;即用例中有
print
等 - a:除了測試通過的啊央,其他所有的;即除了
p
和P
的 - A:所有的
上述字符參數(shù)可以疊加使用涨醋,例如:我們期望過濾出失敗的和未執(zhí)行的:
pytest -rfs
8. 失敗時加載PDB(Python Debugger)環(huán)境
PDB
是python
內(nèi)建的診斷器瓜饥,pytest
允許通過以下命令在執(zhí)行失敗時進(jìn)入這個診斷器模式:
pytest --pdb
pytest
會在測試用例失敗(或者Ctrl+C
)時浴骂,調(diào)用這個診斷器:
# src/chapter-2/test_pdb.py
def test_fail():
x = 1
assert x == 0
$ pipenv run pytest -q --pdb src/chapter-2/test_pdb.py
F
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> traceback >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
def test_fail():
x = 1
> assert x == 0
E assert 1 == 0
src/chapter-2/test_pdb.py:25: AssertionError
>>>>>>>>>>>>>>>>>>>>>>>>>>>>> entering PDB >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> PDB post_mortem (IO-capturing turned off) >>>>>>>>>>>>>>>
> /Users/yaomeng/Private/Projects/pytest-chinese-doc/src/chapter-2/test_pdb.py(25)test_fail()
-> assert x == 0
(Pdb)
(Pdb) x
1
(Pdb)
(Pdb) import sys
(Pdb) sys.last_value
AssertionError('assert 1 == 0')
(Pdb) sys.last_type
<class 'AssertionError'>
(Pdb) sys.last_traceback
<traceback object at 0x1077ec808>
你還可以訪問測試用例的本地變量x
乓土;
失敗的信息存儲在sys.last_value, sys.last_type, sys.last_traceback
變量中,你可以在交互環(huán)境中訪問它們溯警;
使用exit
命令趣苏,退出PDB
環(huán)境;
9. 開始執(zhí)行時就加載PDB
環(huán)境
通過以下命令梯轻,pytest
允許你在每個測試用例開始執(zhí)行時食磕,就加載PDB
環(huán)境:
pytest --trace
10. 設(shè)置斷點
在測試用例代碼中添加import pdb;pdb.set_trace()
,當(dāng)其被調(diào)用時喳挑,pytest
會停止這條用例的輸出:
- 其他用例不受影響彬伦;
- 通過
continue
命令,退出PDB
環(huán)境伊诵,并繼續(xù)執(zhí)行用例媚朦;
11. 使用內(nèi)置的中斷函數(shù)
python 3.7介紹了一個內(nèi)置breakpoint()
函數(shù)。pytest可以在以下場景中支持使用:
- 當(dāng)
breakpoint()
被調(diào)用日戈,并且PYTHONBREAKPOINT
為None
時询张,pytest
會使用內(nèi)部自定義的PDB
代替系統(tǒng)的; - 測試執(zhí)行結(jié)束時浙炼,自動切回系統(tǒng)自帶的
PDB
份氧; - 當(dāng)加上
--pdb
選項時,breakpoint()
和測試發(fā)生錯誤時弯屈,都會調(diào)用內(nèi)部自定義的PDB
蜗帜; -
--pdbcls
選項允許指定一個用戶自定義的PDB
類;
12. 分析測試執(zhí)行時間
獲取執(zhí)行最慢的10個測試用例:
pytest --durations=10
默認(rèn)情況下资厉,pytest
不會顯示執(zhí)行時間<0.01s的測試用例厅缺,可以使用-vv
選項查看它們;
13. 錯誤句柄
5.0版本新增特性
在測試執(zhí)行中發(fā)生段錯誤或者超時的情況下,faulthandler
標(biāo)準(zhǔn)模塊可以轉(zhuǎn)儲python
的回溯信息湘捎;
它在pytest
的執(zhí)行中默認(rèn)使能诀豁,使用-p no:faulthandler
選項可以關(guān)閉它;
同樣窥妇,faulthandler_timeout=X
配置項舷胜,可用于當(dāng)測試用例的完成時間超過X
秒時,轉(zhuǎn)儲所有線程的python
回溯信息:
# src/chapter-2/pytest.ini
[pytest]
faulthandler_timeout=5
配置測試執(zhí)行的超時時間是5秒活翩;
# test_fault_handler.py
import time
def test_faulthandler():
time.sleep(7)
assert 1
測試用例中添加等待7秒的操作烹骨;
-
默認(rèn)使能
faulthandler
的情況:$ pipenv run pytest -q src/chapter-2/test_faulthandler.py Timeout (0:00:05)! Thread 0x000000010ff275c0 (most recent call first): File "/Users/yaomeng/Private/Projects/pytest-chinese-doc/src/chapter-2/test_faulthandler.py", line 26 in test_faulthandler File "/Users/yaomeng/.local/share/virtualenvs/pytest-chinese-doc-EK3zIUmM/lib/python3.7/site-packages/_pytest/python.py", line 170 in pytest_pyfunc_call File "/Users/yaomeng/.local/share/virtualenvs/pytest-chinese-doc-EK3zIUmM/lib/python3.7/site-packages/pluggy/callers.py", line 187 in _multicall File "/Users/yaomeng/.local/share/virtualenvs/pytest-chinese-doc-EK3zIUmM/lib/python3.7/site-packages/pluggy/manager.py", line 86 in <lambda> File "/Users/yaomeng/.local/share/virtualenvs/pytest-chinese-doc-EK3zIUmM/lib/python3.7/site-packages/pluggy/manager.py", line 92 in _hookexec File "/Users/yaomeng/.local/share/virtualenvs/pytest-chinese-doc-EK3zIUmM/lib/python3.7/site-packages/pluggy/hooks.py", line 286 in __call__ File "/Users/yaomeng/.local/share/virtualenvs/pytest-chinese-doc-EK3zIUmM/lib/python3.7/site-packages/_pytest/python.py", line 1423 in runtest File "/Users/yaomeng/.local/share/virtualenvs/pytest-chinese-doc-EK3zIUmM/lib/python3.7/site-packages/_pytest/runner.py", line 117 in pytest_runtest_call File "/Users/yaomeng/.local/share/virtualenvs/pytest-chinese-doc-EK3zIUmM/lib/python3.7/site-packages/pluggy/callers.py", line 187 in _multicall File "/Users/yaomeng/.local/share/virtualenvs/pytest-chinese-doc-EK3zIUmM/lib/python3.7/site-packages/pluggy/manager.py", line 86 in <lambda> File "/Users/yaomeng/.local/share/virtualenvs/pytest-chinese-doc-EK3zIUmM/lib/python3.7/site-packages/pluggy/manager.py", line 92 in _hookexec File "/Users/yaomeng/.local/share/virtualenvs/pytest-chinese-doc-EK3zIUmM/lib/python3.7/site-packages/pluggy/hooks.py", line 286 in __call__ File "/Users/yaomeng/.local/share/virtualenvs/pytest-chinese-doc-EK3zIUmM/lib/python3.7/site-packages/_pytest/runner.py", line 192 in <lambda> File "/Users/yaomeng/.local/share/virtualenvs/pytest-chinese-doc-EK3zIUmM/lib/python3.7/site-packages/_pytest/runner.py", line 220 in from_call File "/Users/yaomeng/.local/share/virtualenvs/pytest-chinese-doc-EK3zIUmM/lib/python3.7/site-packages/_pytest/runner.py", line 192 in call_runtest_hook File "/Users/yaomeng/.local/share/virtualenvs/pytest-chinese-doc-EK3zIUmM/lib/python3.7/site-packages/_pytest/runner.py", line 167 in call_and_report File "/Users/yaomeng/.local/share/virtualenvs/pytest-chinese-doc-EK3zIUmM/lib/python3.7/site-packages/_pytest/runner.py", line 87 in runtestprotocol File "/Users/yaomeng/.local/share/virtualenvs/pytest-chinese-doc-EK3zIUmM/lib/python3.7/site-packages/_pytest/runner.py", line 72 in pytest_runtest_protocol File "/Users/yaomeng/.local/share/virtualenvs/pytest-chinese-doc-EK3zIUmM/lib/python3.7/site-packages/pluggy/callers.py", line 187 in _multicall File "/Users/yaomeng/.local/share/virtualenvs/pytest-chinese-doc-EK3zIUmM/lib/python3.7/site-packages/pluggy/manager.py", line 86 in <lambda> File "/Users/yaomeng/.local/share/virtualenvs/pytest-chinese-doc-EK3zIUmM/lib/python3.7/site-packages/pluggy/manager.py", line 92 in _hookexec File "/Users/yaomeng/.local/share/virtualenvs/pytest-chinese-doc-EK3zIUmM/lib/python3.7/site-packages/pluggy/hooks.py", line 286 in __call__ File "/Users/yaomeng/.local/share/virtualenvs/pytest-chinese-doc-EK3zIUmM/lib/python3.7/site-packages/_pytest/main.py", line 256 in pytest_runtestloop File "/Users/yaomeng/.local/share/virtualenvs/pytest-chinese-doc-EK3zIUmM/lib/python3.7/site-packages/pluggy/callers.py", line 187 in _multicall File "/Users/yaomeng/.local/share/virtualenvs/pytest-chinese-doc-EK3zIUmM/lib/python3.7/site-packages/pluggy/manager.py", line 86 in <lambda> File "/Users/yaomeng/.local/share/virtualenvs/pytest-chinese-doc-EK3zIUmM/lib/python3.7/site-packages/pluggy/manager.py", line 92 in _hookexec File "/Users/yaomeng/.local/share/virtualenvs/pytest-chinese-doc-EK3zIUmM/lib/python3.7/site-packages/pluggy/hooks.py", line 286 in __call__ File "/Users/yaomeng/.local/share/virtualenvs/pytest-chinese-doc-EK3zIUmM/lib/python3.7/site-packages/_pytest/main.py", line 235 in _main File "/Users/yaomeng/.local/share/virtualenvs/pytest-chinese-doc-EK3zIUmM/lib/python3.7/site-packages/_pytest/main.py", line 191 in wrap_session File "/Users/yaomeng/.local/share/virtualenvs/pytest-chinese-doc-EK3zIUmM/lib/python3.7/site-packages/_pytest/main.py", line 228 in pytest_cmdline_main File "/Users/yaomeng/.local/share/virtualenvs/pytest-chinese-doc-EK3zIUmM/lib/python3.7/site-packages/pluggy/callers.py", line 187 in _multicall File "/Users/yaomeng/.local/share/virtualenvs/pytest-chinese-doc-EK3zIUmM/lib/python3.7/site-packages/pluggy/manager.py", line 86 in <lambda> File "/Users/yaomeng/.local/share/virtualenvs/pytest-chinese-doc-EK3zIUmM/lib/python3.7/site-packages/pluggy/manager.py", line 92 in _hookexec File "/Users/yaomeng/.local/share/virtualenvs/pytest-chinese-doc-EK3zIUmM/lib/python3.7/site-packages/pluggy/hooks.py", line 286 in __call__ File "/Users/yaomeng/.local/share/virtualenvs/pytest-chinese-doc-EK3zIUmM/lib/python3.7/site-packages/_pytest/config/__init__.py", line 77 in main File "/Users/yaomeng/.local/share/virtualenvs/pytest-chinese-doc-EK3zIUmM/bin/pytest", line 10 in <module> . [100%] 1 passed in 7.02s
在執(zhí)行剛超過5秒的時候會打印出回溯信息。但不會中斷測試的執(zhí)行材泄;
-
去使能
faulthandler
的情況:$ pipenv run pytest -q -p no:faulthandler src/chapter-2/test_faulthandler.py . [100%] 1 passed in 7.02s
超時并不會觸發(fā)回溯信息的打泳诨馈;
注意:
這個功能是從pytest-faulthandler插件合并而來的拉宗,但是有兩點不同:
- 去使能時遇汞,使用
-p no:faulthandler
代替原來的--no-faulthandler
;- 使用
faulthandler_timeout
配置項代替--faulthandler-timeout
命令行選項來配置超時時間。當(dāng)然簿废,你也可以使用-o faulthandler_timeout=X
在命令行配置;
14. 創(chuàng)建JUnitXML
格式的測試報告
使用如下命令络它,可以在指定的path
中創(chuàng)建一個能被Jenkins或者其他CI工具讀取的XML
格式的測試報告:
pytest --junitxml=path
你可以在項目的pytest.ini
文件中族檬,通過設(shè)置junit_suite_name
的值,自定義XML
文件中testsuite
根節(jié)點的name
信息:
junit_suite_name
是4.0版本新增的配置項化戳;
# src/chapter-2/pytest.ini
[pytest]
junit_suite_name = pytest_chinese_doc
我們來執(zhí)行一個測試用例test_nodeid.py::test_one
看看效果:
pipenv run pytest -q --junitxml=src/chapter-2/report/test_one.xml src/chapter-2/test_nodeid.py::test_one
生成的XML
測試報告:
<?xml version="1.0" encoding="utf-8"?>
<testsuites>
<testsuite errors="0" failures="0" hostname="NJ-LUYAO-T460" name="pytest_chinese_doc" skipped="0" tests="1"
time="0.030" timestamp="2019-09-27T14:33:32.459788">
<testcase classname="test_nodeid" file="test_nodeid.py" line="24" name="test_one" time="0.002">
<system-out>test_one
</system-out>
</testcase>
</testsuite>
</testsuites>
我們可以看到单料,<testsuite>
節(jié)點的name
屬性的值,變?yōu)槲覀兯谕?code>pytest_chinese_doc点楼,而不是默認(rèn)的pytest
扫尖;
JUnit XML規(guī)定time
屬性應(yīng)該表明測試用例執(zhí)行的全部耗時,包含setup
和teardown
中的操作掠廓,這也是pytest的默認(rèn)行為换怖;
如果你只想記錄測試用例執(zhí)行的時間,只需要做如下配置:
# src/chapter-2/pytest.ini
junit_duration_report = call
14.1. 在報告中為測試用例附加額外的子節(jié)點信息
我們有兩種方式實現(xiàn)這個功能:
-
使用
record_property fixture
:為
test_record_property
用例添加一個額外的test_id
:# src/chapter-2/test_xml_report.py def test_record_property(record_property): record_property("test_id", 10010) assert 1
在報告中的表現(xiàn)為
<property name="test_id" value="10010" />
:<!-- src/chapter-2/report/test_record_property.xml --> <?xml version="1.0" encoding="utf-8"?> <testsuites> <testsuite errors="0" failures="0" hostname="NJ-LUYAO-T460" name="pytest_chinese_doc" skipped="0" tests="1" time="0.024" timestamp="2019-09-27T15:02:41.277369"> <testcase classname="test_xml_report" file="test_xml_report.py" line="22" name="test_record_property" time="0.002"> <properties> <property name="test_id" value="10010" /> </properties> </testcase> </testsuite> </testsuites>
-
解析一個自定義的標(biāo)記
@pytest.mark.test_id()
:首先蟀瞧,修改
pytest_collection_modifyitems
鉤子方法沉颂,添加對test_id
標(biāo)記的支持:# src/chapter-2/conftest.py def pytest_collection_modifyitems(session, config, items): for item in items: for marker in item.iter_markers(name="test_id"): test_id = marker.args[0] item.user_properties.append(("test_id", test_id))
然后,修改測試用例:
# src/chapter-2/test_xml_report.py import pytest @pytest.mark.test_id(10010) def test_record_property1(): assert 1
在報告中的也表現(xiàn)為
<property name="test_id" value="10010" />
:<!-- src/chapter-2/report/test_record_property1.xml --> <?xml version="1.0" encoding="utf-8"?> <testsuites> <testsuite errors="0" failures="0" hostname="NJ-LUYAO-T460" name="pytest_chinese_doc" skipped="0" tests="1" time="0.029" timestamp="2019-09-27T15:16:05.309308"> <testcase classname="test_xml_report" file="test_xml_report.py" line="29" name="test_record_property1" time="0.001"> <properties> <property name="test_id" value="10010" /> </properties> </testcase> </testsuite> </testsuites>
注意:
這是我們會接收到一個告警:
PytestUnknownMarkWarning: Unknown pytest.mark.test_id - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/latest/mark.html
這是因為我們沒有在
pytest
中注冊test_id
標(biāo)記悦污,但不影響正常的執(zhí)行铸屉;如果你想去除這個告警,只需要在
pytest.ini
的配置文件中注冊這個標(biāo)記:[pytest] markers = test_id: 為測試用例添加ID
注意:
變動后的報告可能不符合最新的
JUnitXML
的模式檢查規(guī)則切端,導(dǎo)致在某些CI工具上可能會發(fā)生未知的錯誤彻坛;
14.2. 在報告中為測試用例附加額外的屬性信息
可以通過record_xml_attribute fixture
為測試用例附加額外的屬性,而不像record_property
為其添加子節(jié)點;
為測試用例添加一個test_id
屬性昌屉,并修改原先的classname
屬性:
# src/chapter-2/test_xml_report.py
def test_record_property2(record_xml_attribute):
record_xml_attribute('test_id', 10010)
record_xml_attribute('classname', 'custom_classname')
assert 1
在報告中的表現(xiàn)為<testcase classname="custom_classname" test_id="10010" ...
:
<!-- src/chapter-2/report/test_record_property2.xml -->
<?xml version="1.0" encoding="utf-8"?>
<testsuites>
<testsuite errors="0" failures="0" hostname="NJ-LUYAO-T460" name="pytest_chinese_doc" skipped="0" tests="1"
time="0.028" timestamp="2019-09-27T15:35:47.093494">
<testcase classname="custom_classname" file="test_xml_report.py" line="34" name="test_record_property2"
test_id="10010" time="0.001"></testcase>
</testsuite>
</testsuites>
注意:
record_xml_attribute
目前是一個實驗性的功能钙蒙,未來可能被更強大的API所替代,但功能本身會被保留怠益。變動后的報告可能不符合最新的
JUnitXML
的模式檢查規(guī)則仪搔,導(dǎo)致在某些CI工具上可能會發(fā)生未知的錯誤;
14.3. 在報告中為測試集附加額外的子節(jié)點信息
4.5版本新增功能
可以通過自定義一個session
作用域級別的fixture
蜻牢,為測試集添加子節(jié)點信息烤咧,并且會作用于所有的測試用例;
這個自定義的fixture
需要調(diào)用另外一個record_testsuite_property fixture
:
record_testsuite_property
接收兩個參數(shù)name
和value
以構(gòu)成<property>
標(biāo)簽抢呆,其中煮嫌,name
必須為字符串,value
會轉(zhuǎn)換為字符串并進(jìn)行XML轉(zhuǎn)義抱虐;
# src/chapter-2/test_xml_report.py
@pytest.fixture(scope="session")
def log_global_env_facts(record_testsuite_property):
record_testsuite_property("EXECUTOR", "luizyao")
record_testsuite_property("LOCATION", "NJ")
def test_record_property3(log_global_env_facts):
assert 1
生成的測試報告表現(xiàn)為:在testsuite
節(jié)點中昌阿,多了一個properties
子節(jié)點,包含所有新增的屬性節(jié)點恳邀,而且懦冰,它和所有的testcase
節(jié)點是平級的;
<!-- src/chapter-2/report/test_record_property3.xml -->
<?xml version="1.0" encoding="utf-8"?>
<testsuites>
<testsuite errors="0" failures="0" hostname="NJ-LUYAO-T460" name="pytest_chinese_doc" skipped="0" tests="1"
time="0.027" timestamp="2019-09-27T15:52:34.562238">
<properties>
<property name="EXECUTOR" value="luizyao" />
<property name="LOCATION" value="NJ" />
</properties>
<testcase classname="test_xml_report" file="test_xml_report.py" line="46" name="test_record_property3" time="0.002">
</testcase>
</testsuite>
</testsuites>
注意:
這樣生成的XML文件是符合最新的
xunit
標(biāo)準(zhǔn)的谣沸,這點和record_property
刷钢、record_xml_attribute
正好相反;
15. 創(chuàng)建純文本格式的測試報告
不推薦使用乳附,計劃在
pytest 6.0
中刪除這個功能
使用如下命令内地,可以在指定的path
中創(chuàng)建一個純文本的測試報告:
pytest --resultlog=path
16. 為測試報告提供URL
鏈接 -- pastebin
服務(wù)
目前,只實現(xiàn)了在http://bpaste.net上的展示功能赋除;
-
為每一個失敗的測試用例創(chuàng)建一個URL
pytest --pastebin=failed
也可以通過添加
-x
選項阱缓,只為第一個失敗的測試用例創(chuàng)建一個URL; -
為所有的測試用例創(chuàng)建一個URL
pytest --pastebin=all
17. 盡早的加載插件
你可以在命令行中使用-p
選項举农,來盡早的加載某一個插件:
pytest -p mypluginmodule
-p
選項接收一個name
參數(shù)荆针,這個參數(shù)可以為:
一個完整的本地插件引入,例如:
myproject.plugins
颁糟,其必須是可以import
的祭犯。-
一個公共插件的名稱,這是其注冊時在
setuptools
中賦予的名字滚停,例如:盡早的加載pytest-cov插件:pytest -p pytest_cov
18. 去使能插件
你可以在命令行中使用-p
結(jié)合no:
沃粗,來去使能一個插件的加載,例如:
pytest -p no:doctest
19. 在python
代碼中調(diào)用pytest
可以直接在代碼中調(diào)用pytest
:
pytest.main()
這和你在命令行中執(zhí)行pytest .
幾乎是一樣的键畴,但其也有以下特點:
-
不會觸發(fā)
SystemExit
最盅,而是返回exitcode:# src/chapter-2/invoke_via_main.py import time def test_one(): time.sleep(10) if __name__ == '__main__': import pytest ret = pytest.main(['-q', __file__]) print("pytest.main() 返回 pytest.ExitCode.INTERRUPTED:", ret == pytest.ExitCode.INTERRUPTED)
用例中有等待10秒的操作突雪,在這期間,打斷執(zhí)行(
Ctr+C
)涡贱,pytest.main()
返回的是INTERRUPTED
狀態(tài)碼咏删;λ pipenv run python src/chapter-2/invoke_via_main.py !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! KeyboardInterrupt !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! D:\Personal Files\Projects\pytest-chinese-doc\src\chapter-2\invoke_via_main.py:26: KeyboardInterrupt (to show a full traceback on KeyboardInterrupt use --full-trace) no tests ran in 1.04s pytest.main() 返回 pytest.ExitCode.INTERRUPTED: True Aborted!
-
傳遞選項和參數(shù):
pytest.main(["-x", "mytestdir"])
-
指定一個插件:
import pytest class MyPlugin: def pytest_sessionfinish(self): print("*** test run reporting finishing") pytest.main(["-qq"], plugins=[MyPlugin()])
注意:
調(diào)用
pytest.main()
會引入你的測試文件以及其引用的所有模塊。由于python引入機制的緩存特性问词,當(dāng)這些文件發(fā)生變化時督函,后續(xù)再調(diào)用pytest.main()
(在同一個程序執(zhí)行過程中)時,并不會響應(yīng)這些文件的變化激挪。基于這個原因辰狡,我們不推薦在同一個程序中多次調(diào)用
pytest.main()
(例如:為了重新執(zhí)行測試;如果你確實有這個需求垄分,或許可以考慮pytest-repeat插件)宛篇;