目錄:
- 安裝及入門
- 使用和調用方法
- 原有TestSuite使用方法
- 斷言的編寫和報告
- Pytest fixtures:清晰 模塊化 易擴展
- 使用Marks標記測試用例
- Monkeypatching/對模塊和環(huán)境進行Mock
- 使用tmp目錄和文件
- 捕獲stdout及stderr輸出
- 捕獲警告信息
- 模塊及測試文件中集成doctest測試
- skip及xfail: 處理不能成功的測試用例
- Fixture方法及測試用例的參數化
- 緩存: 使用跨執(zhí)行狀態(tài)
- unittest.TestCase支持
- 運行Nose用例
- 經典xUnit風格的setup/teardown
- 安裝和使用插件
- 插件編寫
- 編寫鉤子(hook)方法
- 運行日志
- API參考
- 優(yōu)質集成實踐
- 片狀測試
- Pytest導入機制及sys.path/PYTHONPATH
- 配置選項
- 示例及自定義技巧
- Bash自動補全設置
使用和調用方法
使用python -m pytest調用pytest
2.0版本新增
你可以在命令行中通過Python編譯器來調用pytest執(zhí)行測試
python -m pytest [...]
通過python
調用會將當前目錄也添加到sys.path
中蓖扑,除此之外,這幾乎等同于命令行直接調用pytest [...]
。
可能出現的執(zhí)行退出code
執(zhí)行pytest
可能會出現6中不同的退出code:
- 退出code 0: 收集并成功通過所有測試用例
- 退出code 1: 收集并運行了測試根穷,部分測試用例執(zhí)行失敗
- 退出code 2: 測試執(zhí)行被用戶中斷
- 退出code 3: 執(zhí)行測試中發(fā)生內部錯誤
- 退出code 4: pytest命令行使用錯誤
- 退出code 5: 沒有收集到測試用例
獲取版本路徑、命令行選項及環(huán)境變量相關幫助
pytest --version # 顯示pytest導入位置
pytest --fixtures # 顯示可用的內置方法參數
pytest -h | --help # 顯示命令行及配置文件選項幫助信息
第1(N)次失敗后停止測試
在第1(N)次用例失敗后停止測試執(zhí)行:
pytest -x # 第1次失敗后停止
pytest --maxfail=2 # 2次失敗后停止
指定及選擇測試用例
Pytest支持多種從命令行運行和選擇測試用例的方法弃理。
運行模塊內所有用例
pytest test_mod.py
運行目錄內所有用例
pytest testing/
按關鍵字表達式運行測試
pytest -k "MyClass and not method"
這將運行包含與給定字符串表達式匹配的名稱的測試用例,其中可以包括文件名屎蜓、類名和函數名作為變量及Python運算符操作痘昌。上面的示例將運行TestMyClass.test_something
但不運行TestMyClass.test_method_simple
。
按節(jié)點id運行測試
每次執(zhí)行收集到的測試集合都會被分配一個唯一的nodeid
梆靖,其中包含模塊文件名控汉,后跟說明符,如類名返吻、函數名及參數姑子,由::
字符分隔。
執(zhí)行模塊中某條指定的測試用例:
pytest test_mod.py::test_func
另一個通過命令行挑選所執(zhí)行測試方法的示例:
pytest test_mod.py::TestClass::test_method
通過標記表達式運行測試
pytest -m slow
這將會執(zhí)行所有帶@pytest.mark.slow
裝飾器的用例测僵。
有關更多信息街佑,請參閱標記
從包中運行測試
pytest --pyargs pkg.testing
這將會導入pkg.testing
并使用其文件系統(tǒng)位置來查找和運行測試。
修改Python追溯(traceback)信息
修改回追溯信息示例:
pytest --showlocals # 在追溯信息中顯示局部變量
pytest -l # 顯示局部變量 (簡寫)
pytest --tb=auto # (默認) 第1和最后1條使用詳細追溯信息捍靠,其他使用簡短追溯信息
pytest --tb=long # 詳盡沐旨,信息豐富的追溯信息格式
pytest --tb=short # 簡短的追溯信息格式
pytest --tb=line # 每個失敗信息一行
pytest --tb=native # Python標準庫格式
pytest --tb=no # 不使用追溯信息
詳盡的摘要報告
2.9版本新增
-r
標志可用于在測試會話結束時顯示測試結果摘要,從而可以在大型測試套件中輕松獲得所有失敗榨婆、跳過磁携、標記失敗(xfails)等測試結果的清晰圖像。
例如:
$ pytest -ra
=========================== test session starts ============================
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y
rootdir: $REGENDOC_TMPDIR, inifile:
collected 0 items
======================= no tests ran in 0.12 seconds =======================
-r
選項接受后面的多個字符良风,上面使用的a
表示“除了執(zhí)行通過(Pass)以外所有的結果”谊迄。
以下是可以使用的可用字符的完整列表:
-f
- 失敗的用例
-E
- 出錯的用例
-s
- 跳過的用例
-x
- 標記失敗的用例
-X
- 標記成功的用例
-p
- 成功用例
-P
- 成功用例并輸出信息
-a
- 所有pP
狀態(tài)以外的用例
可以使用多個字符闷供,例如,只查看失敗和跳過的用例统诺,你可以執(zhí)行:
$ pytest -rfs
=========================== test session starts ============================
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y
rootdir: $REGENDOC_TMPDIR, inifile:
collected 0 items
======================= no tests ran in 0.12 seconds =======================
執(zhí)行失敗時進入PDB (Python調試器)
Python附帶一個名為PDB的內置Python調試器歪脏。 pytest允許通過命令行選項進入PDB提示符:
pytest --pdb
這將在每次失敗(或KeyboardInterrupt)時調用Python調試器。一般粮呢,你可能只希望在第一次失敗的測試中執(zhí)行此操作以了解某種故障情況:
pytest -x --pdb # 在第一次用例失敗時進入PDB
pytest --pdb --maxfail=3 # 在前3次失敗是進入PDB
注意婿失,在任何失敗時,異常信息都存儲在`sys.last_value1啄寡,1sys.last_type1和1sys.last_traceback1中豪硅。在交互模式中,這允許用戶使用任何調試工具進行事后調試这难。也可以手動訪問異常信息舟误,例如:
>>> import sys
>>> sys.last_traceback.tb_lineno
42
>>> sys.last_value
AssertionError('assert result == "ok"',)
測試開始時進入PDB(Python調試器)
pytest
允許用戶通過命令行選項在每次測試開始時立即進入PDB提示符:
pytest --trace
這將在每次測試開始時調用Python調試器葡秒。
設置斷點
要在代碼中設置斷點姻乓,需要在代碼中使用Python原生import pdb; pdb.set_trace()
進行調用,pytest會自動禁用顯示并捕獲該用例輸出結果:
- 其他測試中的輸出捕獲不受影響眯牧。
- 任何先前的測試輸出已經被捕獲并將被處理蹋岩。
- 在同一測試中生成的任何后續(xù)輸出都不會被捕獲,而是直接發(fā)送到
sys.stdout
学少。注意:即使是退出交互式PDB跟蹤會話并繼續(xù)常規(guī)測試后發(fā)生的測試輸出剪个,這也適用。
使用內置斷點方法
Python 3.7引入了內置breakpoint()
函數版确。 Pytest支持以下幾種使用breakpoint()
的方式:
- 當
PYTHONBREAKPOINT
設置為默認值扣囊,調用breakpoint()
時,pytest將使用其內部PDB跟蹤交互界面(PDB trace UI)而不是Python自帶的Pdb
绒疗。 - 測試完成后侵歇,默認會重置為Python自帶的PDB跟蹤交互界面。
- 在pytest后使用
--pdb
參數吓蘑,在失敗的測試/未處理異常中惕虑,pytest內部PDB跟蹤交互界面與breakpoint()
同時使用。 -
--pdbcls
參數可指定要使用的調試器類磨镶。
分析測試執(zhí)行持續(xù)時間
顯示執(zhí)行最慢的10條測試用例:
pytest --durations=10
除非在命令行上傳遞-vv
溃蔫,默認情況下,否則pytest不會顯示<0.01s的測試時間琳猫。
創(chuàng)建JUnitXML格式文件
要創(chuàng)建可由Jenkins或其他持續(xù)集成軟件讀取的XML測試報告伟叛,可以使用:
pytest --junitxml=path
運行結束后,在指定路徑path
下創(chuàng)建一個XML報告文件
3.1版本新增
可以通過修改配置中junit_suite_name
字段的名稱來更改XML報告中root test suite
的名稱脐嫂。
[pytest]
junit_suite_name = my_suite
record_property(添加新屬性)
版本2.8新增
版本3.5更改: 在所有報告生成器(reporter)中用戶屬性record_xml_property
項已改為record_property
统刮,record_xml_property
現已棄用侄榴。
可以使用record_property
項來在XML報告中增加更多的日志信息:
def test_function(record_property):
record_property("example_key", 1)
assert True
在生成的testcase
標簽是會添加一個額外的屬性example_key="1"
:
<testcase classname="test_function" file="test_function.py" line="0" name="test_function" time="0.0009">
<properties>
<property name="example_key" value="1" />
</properties>
</testcase>
或者,你可以將此功能集成在自定義標記裝飾器中:
# 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))
在你的測試用例中使用:
# test_function.py文件內容
import pytest
@pytest.mark.test_id(1501)
def test_function():
assert True
這將導致:
<testcase classname="test_function" file="test_function.py" line="0" name="test_function" time="0.0009">
<properties>
<property name="test_id" value="1501" />
</properties>
</testcase>
警告:
record_property
是一個實驗性功能网沾,將來可能會發(fā)生變化癞蚕。
另外,這將破壞一些XML結構驗證辉哥,與某些持續(xù)集成軟件一起使用時桦山,可能會導致一些問題。
record_xml_attribute(修改xml節(jié)點屬性)
3.4版本新增
可以使用record_xml_attribute fixture向
testcase`標簽中添加其他xml屬性醋旦。也可以用來覆蓋原有屬性值:
def test_function(record_xml_attribute):
record_xml_attribute("assertions", "REQ-1234")
record_xml_attribute("classname", "custom_classname")
print("hello world")
assert True
與record_property
不同恒水, 它不會在節(jié)點下添加子元素,而是在生成的testcase
標簽內添加一個屬性assertions ="REQ-1234"
饲齐,并使用classname = custom_classname
覆蓋默認的classname
屬性:
<testcase classname="custom_classname" file="test_function.py" line="0" name="test_function" time="0.003" assertions="REQ-1234">
<system-out>
hello world
</system-out>
</testcase>
警告:
record_xml_attribute
也是一個實驗性功能钉凌,其界面可能會被更強大,更通用的未來版本所取代捂人。但是御雕,將保留功能本身。
通過使用record_xml_property
可以為在使用持續(xù)集成工具解析xml報告時提供幫助滥搭。 但是酸纲,一些解析器對允許的元素和屬性非常嚴格。 許多工具使用xsd模式(如下例所示)來驗證傳入的xml瑟匆。 確保使用解析器允許的屬性名稱闽坡。
以下是Jenkins用于驗證xml報告的結構:
<xs:element name="testcase">
<xs:complexType>
<xs:sequence>
<xs:element ref="skipped" minOccurs="0" maxOccurs="1"/>
<xs:element ref="error" minOccurs="0" maxOccurs="unbounded"/>
<xs:element ref="failure" minOccurs="0" maxOccurs="unbounded"/>
<xs:element ref="system-out" minOccurs="0" maxOccurs="unbounded"/>
<xs:element ref="system-err" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
<xs:attribute name="name" type="xs:string" use="required"/>
<xs:attribute name="assertions" type="xs:string" use="optional"/>
<xs:attribute name="time" type="xs:string" use="optional"/>
<xs:attribute name="classname" type="xs:string" use="optional"/>
<xs:attribute name="status" type="xs:string" use="optional"/>
</xs:complexType>
</xs:element>
LogXML: add_global_property
3.0版本新增
如果要在testsuite
級別添加屬性節(jié)點,該節(jié)點可能包含與所有測試用例相關的屬性愁溜,則可以使用LogXML.add_global_properties
import pytest
@pytest.fixture(scope="session")
def log_global_env_facts(f):
if pytest.config.pluginmanager.hasplugin("junitxml"):
my_junit = getattr(pytest.config, "_xml", None)
my_junit.add_global_property("ARCH", "PPC")
my_junit.add_global_property("STORAGE_TYPE", "CEPH")
@pytest.mark.usefixtures(log_global_env_facts.__name__)
def start_and_prepare_env():
pass
class TestMe(object):
def test_foo(self):
assert True
這會在生成的xml中的testsuite
節(jié)點下的屬性節(jié)中添加:
<testsuite errors="0" failures="0" name="pytest" skips="0" tests="1" time="0.006">
<properties>
<property name="ARCH" value="PPC"/>
<property name="STORAGE_TYPE" value="CEPH"/>
</properties>
<testcase classname="test_me.TestMe" file="test_me.py" line="16" name="test_foo" time="0.000243663787842"/>
</testsuite>
警告:
這仍然是一個實驗性功能疾嗅,其界面也可能會被更強大,更通用的未來版本所取代冕象, 但也將保留該功能代承。
創(chuàng)建結果日志格式文件
3.0版本之后不推薦使用,計劃在4.0版本
中刪除交惯。
對于仍然需要類似功能的用戶來說次泽,可以使用提供測試數據流的pytest-tap
插件。
如有任何疑慮席爽,可以建立一個問題(open an issue)意荤。
pytest --resultlog=path
執(zhí)行后,在path
路徑中會創(chuàng)建一個純文本結果日志文件只锻,這些文件可以用于:例如玖像,在PyPy-test
網頁顯示多個修訂版的測試結果。
將測試報告發(fā)送到在線pastebin服務
為每條測試失敗用例建立一個日志URL鏈接:
pytest --pastebin=failed
這會將測試運行信息提交到一個提供粘貼服務的遠程服務器上,并為每條測試失敗用例提供一個URL捐寥。 您可以像平常一樣查看搜集結果笤昨,或者使用-x
參數,來只顯示某個特定的測試失敗結果握恳。
為整個測試執(zhí)行日志建立一個URL鏈接:
pytest --pastebin=all
目前只實現了粘貼到http://bpaste.net網站的服務瞒窒。
禁用插件
可以通過-p
選項與前綴no:
一起使用,來在運行時禁用加載特定插件乡洼。
例如:要禁用加載從文本文件執(zhí)行doctest測試的doctest
插件崇裁,可以通過以下方式運行pytest:
pytest -p no:doctest
在Python代碼調用pytest
版本2.0新增
你可以在Python代碼中直接調用pytest:
pytest.main()
這就和你從命令行調用“pytest”一樣。但它不會引發(fā)SystemExit
束昵,而是返回exitcode
拔稳。 你可以傳入選項和參數。
pytest.main(['-x', 'mytestdir'])
您可以為pytest.main
指定其他插件:
# myinvoke.py文件內容
import pytest
class MyPlugin(object):
def pytest_sessionfinish(self):
print("*** test run reporting finishing")
pytest.main(["-qq"], plugins=[MyPlugin()])
運行它將顯示已添加MyPlugin并調用其中的hook方法:
$ python myinvoke.py
. [100%]*** test run reporting finishing
注意:
調用pytest.main()
將會導入所有測試用例及其導入的其他模塊锹雏。由于python導入系統(tǒng)的緩存機制巴比,從同一進程后續(xù)調用pytest.main()
不會反映調用之間對這些文件的更改。 因此礁遵,不建議從同一進程(例如轻绞,為了新運行測試)多次調用pytest.main()
。