Pytest官方教程-02-使用和調用方法

目錄:

  1. 安裝及入門
  2. 使用和調用方法
  3. 原有TestSuite使用方法
  4. 斷言的編寫和報告
  5. Pytest fixtures:清晰 模塊化 易擴展
  6. 使用Marks標記測試用例
  7. Monkeypatching/對模塊和環境進行Mock
  8. 使用tmp目錄和文件
  9. 捕獲stdout及stderr輸出
  10. 捕獲警告信息
  11. 模塊及測試文件中集成doctest測試
  12. skip及xfail: 處理不能成功的測試用例
  13. Fixture方法及測試用例的參數化
  14. 緩存: 使用跨執行狀態
  15. unittest.TestCase支持
  16. 運行Nose用例
  17. 經典xUnit風格的setup/teardown
  18. 安裝和使用插件
  19. 插件編寫
  20. 編寫鉤子(hook)方法
  21. 運行日志
  22. API參考
    1. 方法(Functions)
    2. 標記(Marks)
    3. 鉤子(Hooks)
    4. 裝置(Fixtures)
    5. 對象(Objects)
    6. 特殊變量(Special Variables)
    7. 環境變量(Environment Variables)
    8. 配置選項(Configuration Options)
  23. 優質集成實踐
  24. 片狀測試
  25. Pytest導入機制及sys.path/PYTHONPATH
  26. 配置選項
  27. 示例及自定義技巧
  28. Bash自動補全設置

使用和調用方法

使用python -m pytest調用pytest

2.0版本新增
你可以在命令行中通過Python編譯器來調用pytest執行測試

python -m pytest [...]

通過python調用會將當前目錄也添加到sys.path中,除此之外,這幾乎等同于命令行直接調用pytest [...]

可能出現的執行退出code

執行pytest可能會出現6中不同的退出code:

  • 退出code 0: 收集并成功通過所有測試用例
  • 退出code 1: 收集并運行了測試,部分測試用例執行失敗
  • 退出code 2: 測試執行被用戶中斷
  • 退出code 3: 執行測試中發生內部錯誤
  • 退出code 4: pytest命令行使用錯誤
  • 退出code 5: 沒有收集到測試用例

獲取版本路徑、命令行選項及環境變量相關幫助

pytest --version   # 顯示pytest導入位置
pytest --fixtures  # 顯示可用的內置方法參數
pytest -h | --help # 顯示命令行及配置文件選項幫助信息

第1(N)次失敗后停止測試

在第1(N)次用例失敗后停止測試執行:

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
按節點id運行測試
每次執行收集到的測試集合都會被分配一個唯一的nodeid,其中包含模塊文件名,后跟說明符,如類名、函數名及參數,由:: 字符分隔。
執行模塊中某條指定的測試用例:

pytest test_mod.py::test_func

另一個通過命令行挑選所執行測試方法的示例:

pytest test_mod.py::TestClass::test_method

通過標記表達式運行測試

pytest -m slow

這將會執行所有帶@pytest.mark.slow裝飾器的用例。
有關更多信息,請參閱標記
從包中運行測試

pytest --pyargs pkg.testing

這將會導入pkg.testing并使用其文件系統位置來查找和運行測試。

修改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表示“除了執行通過(Pass)以外所有的結果”。
以下是可以使用的可用字符的完整列表:
-f - 失敗的用例
-E - 出錯的用例
-s - 跳過的用例
-x - 標記失敗的用例
-X - 標記成功的用例
-p - 成功用例
-P - 成功用例并輸出信息
-a - 所有pP狀態以外的用例

可以使用多個字符,例如,只查看失敗和跳過的用例,你可以執行:

$ 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 =======================

執行失敗時進入PDB (Python調試器)

Python附帶一個名為PDB的內置Python調試器。 pytest允許通過命令行選項進入PDB提示符:

pytest --pdb

這將在每次失敗(或KeyboardInterrupt)時調用Python調試器。一般,你可能只希望在第一次失敗的測試中執行此操作以了解某種故障情況:

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會自動禁用顯示并捕獲該用例輸出結果:

  • 其他測試中的輸出捕獲不受影響。
  • 任何先前的測試輸出已經被捕獲并將被處理。
  • 在同一測試中生成的任何后續輸出都不會被捕獲,而是直接發送到sys.stdout。注意:即使是退出交互式PDB跟蹤會話并繼續常規測試后發生的測試輸出,這也適用。

使用內置斷點方法

Python 3.7引入了內置breakpoint()函數。 Pytest支持以下幾種使用breakpoint()的方式:

  • PYTHONBREAKPOINT設置為默認值,調用breakpoint()時,pytest將使用其內部PDB跟蹤交互界面(PDB trace UI)而不是Python自帶的Pdb
  • 測試完成后,默認會重置為Python自帶的PDB跟蹤交互界面。
  • 在pytest后使用--pdb參數,在失敗的測試/未處理異常中,pytest內部PDB跟蹤交互界面與breakpoint()同時使用。
  • --pdbcls參數可指定要使用的調試器類。

分析測試執行持續時間

顯示執行最慢的10條測試用例:

pytest --durations=10

除非在命令行上傳遞-vv,默認情況下,否則pytest不會顯示<0.01s的測試時間。

創建JUnitXML格式文件

要創建可由Jenkins或其他持續集成軟件讀取的XML測試報告,可以使用:

pytest --junitxml=path

運行結束后,在指定路徑path下創建一個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_propertyrecord_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是一個實驗性功能,將來可能會發生變化。
另外,這將破壞一些XML結構驗證,與某些持續集成軟件一起使用時,可能會導致一些問題。

record_xml_attribute(修改xml節點屬性)
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不同, 它不會在節點下添加子元素,而是在生成的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可以為在使用持續集成工具解析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級別添加屬性節點,該節點可能包含與所有測試用例相關的屬性,則可以使用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節點下的屬性節中添加:

<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>

警告:
這仍然是一個實驗性功能,其界面也可能會被更強大,更通用的未來版本所取代, 但也將保留該功能。

創建結果日志格式文件

3.0版本之后不推薦使用,計劃在4.0版本中刪除。

對于仍然需要類似功能的用戶來說,可以使用提供測試數據流的pytest-tap插件。

如有任何疑慮,可以建立一個問題(open an issue)

pytest --resultlog=path

執行后,在path路徑中會創建一個純文本結果日志文件,這些文件可以用于:例如,在PyPy-test網頁顯示多個修訂版的測試結果。

將測試報告發送到在線pastebin服務

為每條測試失敗用例建立一個日志URL鏈接:

pytest --pastebin=failed

這會將測試運行信息提交到一個提供粘貼服務的遠程服務器上,并為每條測試失敗用例提供一個URL。 您可以像平常一樣查看搜集結果,或者使用-x參數,來只顯示某個特定的測試失敗結果。

為整個測試執行日志建立一個URL鏈接:

pytest --pastebin=all

目前只實現了粘貼到http://bpaste.net網站的服務。

禁用插件

可以通過-p選項與前綴no:一起使用,來在運行時禁用加載特定插件。

例如:要禁用加載從文本文件執行doctest測試的doctest插件,可以通過以下方式運行pytest:

pytest -p no:doctest

在Python代碼調用pytest

版本2.0新增
你可以在Python代碼中直接調用pytest:

pytest.main()

這就和你從命令行調用“pytest”一樣。但它不會引發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導入系統的緩存機制,從同一進程后續調用pytest.main()不會反映調用之間對這些文件的更改。 因此,不建議從同一進程(例如,為了新運行測試)多次調用pytest.main()

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容