pytest教程(二)--------使用和調用

上一節我們介紹了pytest的安裝和簡單使用,這一節我們再加些料

pytest不僅容易編寫小的測試例,也支持程序和庫相關的複雜函數測試

 

通過python -m pytest來調用pytest

python -m pytest [...]

這和直接使用pytest命令功能相同,唯一的區別是會將當前目錄加入到sys.path中.

 

可能的退出碼

調用pytest可能產生6種不同的退出碼

Exit code 0: 所有的測試例都被收集且通過
Exit code 1: 所有的測試例都被收集但有部分失敗
Exit code 2: 測試例執行被用戶中斷
Exit code 3: 發生了內部錯誤
Exit code 4: pytest命令行使用錯誤
Exit code 5: 沒用收集到測試例

 

pytest的退出碼API

from pytest import ExitCode

如果你需要在某些場景下定製ExiCode,可以使用pytest-custom_exit_code插件

 

pytest幫助命令

pytest --version   # shows where pytest was imported from
pytest --fixtures  # show available builtin function arguments
pytest -h | --help # show help on command line and config file options

 

在測試例失敗指定個數後停止pytest

pytest -x           # stop after first failure
pytest --maxfail=2  # stop after two failures

 

選擇指定的測試例運行

pytest支持多種方式選擇要運行的測試例

運行指定的模塊

pytest test_mod.py

運行指定的目錄

pytest testing/

指定關鍵字運行

pytest -k "MyClass and not method"

上面的命令將會運行名字滿足上面字符串表達式的用例,字符串表達式可以包含文件名,類名,函數名。上面的例子會運行TestMyClass.test_something,但不會運行TestMyClass.test_method_simple.

 

指定node ids運行

每個測試例都有一個唯一的nodeid,由模塊名::類名::函數名組成。

運行指定模塊中的測試例:

pytest test_mod.py::test_func

運行指定模塊中指定類中的指定函數

pytest test_mod.py::test_func

指定marker表達式運行

pytest -m slow

上面的命令將會運行所有被@pytest.mark.slow 裝飾的測試例 

 

運行指定包中的測試例

pytest --pyargs pkg.testing

 

修改python打印traceback的方式

pytest --showlocals # show local variables in tracebacks
pytest -l           # show local variables (shortcut)

pytest --tb=auto    # (default) 'long' tracebacks for the first and last
                     # entry, but 'short' style for the other entries
pytest --tb=long    # exhaustive, informative traceback formatting
pytest --tb=short   # shorter traceback format
pytest --tb=line    # only one line per failure
pytest --tb=native  # Python standard library formatting
pytest --tb=no      # no traceback at all

"--full-trace”會在發生錯誤時打印很長的回溯棧,同時也能保證在KeyboardInterrupt (Ctrl+C)時打印棧.

在測試長時間運行不中止時我們用Ctrl+C中止後十分有用,便於我們發現問題所在。

通常情況下,pytests會捕獲Ctrl+C因此不會打印棧信息。使用這個選項能夠確保顯示trace信息。

 

詳細的總結報告

"-r"選項用於在測試結束時顯示一個簡短的測試總結信息。這便於我們在大的測試套件中獲取失敗,跳過用例的清晰信息。

默認情況下,pytest使用"fE"來顯示失敗和錯誤.

舉例:

# content of test_example.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
$ pytest -ra
=========================== test session starts ============================
platform linux -- Python 3.x.y, pytest-5.x.y, py-1.x.y, pluggy-0.x.y
cachedir: $PYTHON_PREFIX/.pytest_cache
rootdir: $REGENDOC_TMPDIR
collected 6 items

test_example.py .FEsxX                                               [100%]

================================== ERRORS ==================================
_______________________ ERROR at setup of test_error _______________________

    @pytest.fixture
    def error_fixture():
>       assert 0
E       assert 0

test_example.py:6: AssertionError
================================= FAILURES =================================
________________________________ test_fail _________________________________

    def test_fail():
>       assert 0
E       assert 0

test_example.py:14: AssertionError
========================= short test summary info ==========================
SKIPPED [1] $REGENDOC_TMPDIR/test_example.py:22: skipping this test
XFAIL test_example.py::test_xfail
  reason: xfailing this test
XPASS test_example.py::test_xpass always xfail
ERROR test_example.py::test_error - assert 0
FAILED test_example.py::test_fail - assert 0
== 1 failed, 1 passed, 1 skipped, 1 xfailed, 1 xpassed, 1 error in 0.12s ===

-r選項後面可以接受一系列字符,'a'表示除了所有通過以外的測試例

下面是所有可以使用的字符:

  • f - failed
  • E - error
  • s - skipped
  • x - xfailed
  • X - xpassed
  • p - passed
  • P - passed with output

用於選擇和反選擇的特殊字符:

  • a - all except pP
  • A - all
  • N - none, this can be used to display nothing (since fE is the default)

可以指定多個字符,下面的例子中只顯示失敗和跳過的測試例:

=========================== test session starts ============================
platform linux -- Python 3.x.y, pytest-5.x.y, py-1.x.y, pluggy-0.x.y
cachedir: $PYTHON_PREFIX/.pytest_cache
rootdir: $REGENDOC_TMPDIR
collected 6 items

test_example.py .FEsxX                                               [100%]

================================== ERRORS ==================================
_______________________ ERROR at setup of test_error _______________________

    @pytest.fixture
    def error_fixture():
>       assert 0
E       assert 0

test_example.py:6: AssertionError
================================= FAILURES =================================
________________________________ test_fail _________________________________

    def test_fail():
>       assert 0
E       assert 0

test_example.py:14: AssertionError
========================= short test summary info ==========================
FAILED test_example.py::test_fail - assert 0
SKIPPED [1] $REGENDOC_TMPDIR/test_example.py:22: skipping this test
== 1 failed, 1 passed, 1 skipped, 1 xfailed, 1 xpassed, 1 error in 0.12s ===

使用p展示通過的測試例,P添加額外的"PASSES"來展示:

$ pytest -rpP
=========================== test session starts ============================
platform linux -- Python 3.x.y, pytest-5.x.y, py-1.x.y, pluggy-0.x.y
cachedir: $PYTHON_PREFIX/.pytest_cache
rootdir: $REGENDOC_TMPDIR
collected 6 items

test_example.py .FEsxX                                               [100%]

================================== ERRORS ==================================
_______________________ ERROR at setup of test_error _______________________

    @pytest.fixture
    def error_fixture():
>       assert 0
E       assert 0

test_example.py:6: AssertionError
================================= FAILURES =================================
________________________________ test_fail _________________________________

    def test_fail():
>       assert 0
E       assert 0

test_example.py:14: AssertionError
================================== PASSES ==================================
_________________________________ test_ok __________________________________
--------------------------- Captured stdout call ---------------------------
ok
========================= short test summary info ==========================
PASSED test_example.py::test_ok
== 1 failed, 1 passed, 1 skipped, 1 xfailed, 1 xpassed, 1 error in 0.12s ===

失敗時使用PDB(Python Debugger)

pytest --pdb

控制使用PDB的條件

pytest -x --pdb   # drop to PDB on first failure, then end test session
pytest --pdb --maxfail=3  # drop to PDB for first three failures

注意當失敗時,異常信息會存儲到sys.last_valuesys.last_type 和sys.last_traceback. 在交互模式下,這允許我們在用debug工具在事後進行分析。你也可以手動訪問異常信息:

>>> import sys
>>> sys.last_traceback.tb_lineno
42
>>> sys.last_value
AssertionError('assert result == "ok"',)

在測試開始時進入PDB

pytest --trace

上面的命令將會在每個測試例開始時進入PDB.

 

使用斷點

要在代碼裏設置斷點,使用原生的Python方法:

    def test_two(self):
        x = "hello"
        import pdb
        pdb.set_trace()
        assert hasattr(x, "check")

使用內置的breakpoint函數

python3.7提供了內置的breakpoint函數,pytest支持的breakpoint函數有以下行爲:

  • When breakpoint() is called and PYTHONBREAKPOINT is set to the default value, pytest will use the custom internal PDB trace UI instead of the system default Pdb.
  • When tests are complete, the system will default back to the system Pdb trace UI.
  • With --pdb passed to pytest, the custom internal Pdb trace UI is used with both breakpoint() and failed tests/unhandled exceptions.
  • --pdbcls can be used to specify a custom debugger class.

 

分析測試執行時間

得到執行最慢的10個測試

pytest --durations=10

默認情況下,pytest不顯示執行時間特別短的測試(<0.01s),除非使用-vv選項。

===================================================================================================== slowest 2 test durations ======================================================================================================
1.81s call     test_class.py::TestClass::test_two
0.01s setup    test_tmpdir.py::test_needsfiles

 

缺陷處理

從5.0版本開始支持

faulthandler標準庫用於在產生段錯誤或超時時dump Python tracebacks. 

這個模塊在pytest中自動加載,除非使用 -p no:faulthandler.

 faulthandler_timeout=X配置可以用於 dump所有線程的traceback,如果一個測試例運行超過X秒(在Windows上不支持).

 

提前加載插件

pytest -p mypluginmodule

禁用插件

pytest -p no:doctest

 

在Python代碼中使用pytest

pytest.main()

使用參數

pytest.main(["-x", "mytestdir"])

指定額外插件

# content of myinvoke.py
import pytest


class MyPlugin:
    def pytest_sessionfinish(self):
        print("*** test run reporting finishing")


pytest.main(["-qq"], plugins=[MyPlugin()])
$ python myinvoke.py
.FEsxX.                                                              [100%]*** test run reporting finishing

================================== ERRORS ==================================
_______________________ ERROR at setup of test_error _______________________

    @pytest.fixture
    def error_fixture():
>       assert 0
E       assert 0

test_example.py:6: AssertionError
================================= FAILURES =================================
________________________________ test_fail _________________________________

    def test_fail():
>       assert 0
E       assert 0

test_example.py:14: AssertionError
========================= short test summary info ==========================
FAILED test_example.py::test_fail - assert 0
ERROR test_example.py::test_error - assert 0

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章