您可以標(biāo)記不能在某些平臺上運(yùn)行的測試函數(shù),或者您預(yù)計(jì)會失敗的測試函數(shù),以便pytest可以相應(yīng)地處理它們,并顯示測試會話的摘要,同時保持測試套件為綠色。
?skip
?意味著您希望您的測試只有在滿足某些條件時才會通過,否則pytest應(yīng)該完全跳過運(yùn)行測試。常見的例子是跳過非windows平臺上的僅限windows的測試,或者跳過依賴于當(dāng)前不可用的外部資源(例如數(shù)據(jù)庫)的測試。
?xfail
?意味著您預(yù)期測試由于某種原因會失敗。一個常見的例子是對尚未實(shí)現(xiàn)的特性或尚未修復(fù)的bug進(jìn)行測試。當(dāng)測試通過時,盡管預(yù)期會失敗(標(biāo)記為?pytest.mark.xfail
?),它是一個?xpass
?,并將在測試總結(jié)中報告。
Pytest分別計(jì)數(shù)和列出?skip
?和?xfail
?測試。默認(rèn)情況下,不顯示有關(guān)?skip
?/?xfailed
?測試的詳細(xì)信息,以避免輸出混亂。你可以使用?-r
?選項(xiàng)來查看測試進(jìn)度中顯示的?short
?字母對應(yīng)的詳細(xì)信息:
pytest -rxXs # show extra info on xfailed, xpassed, and skipped tests
通過運(yùn)行 ?pytest -h
? 可以找到有關(guān) ?-r
選項(xiàng)的更多詳細(xì)信息。
跳過一個測試函數(shù)的最簡單的方法是用?skip
?裝飾器來標(biāo)記它,它可以傳遞一個可選的原因:
@pytest.mark.skip(reason="no way of currently testing this")
def test_the_unknown():
...
或者,也可以通過調(diào)用 ?pytest.skip(reason)
? 函數(shù)在測試執(zhí)行或設(shè)置期間強(qiáng)制跳過:
def test_function():
if not valid_config():
pytest.skip("unsupported configuration")
當(dāng)在導(dǎo)入期間無法評估跳過條件時,命令式方法很有用。
也可以在模塊級別使用 ?pytest.skip(reason, allow_module_level=True)
? 跳過整個模塊:
import sys
import pytest
if not sys.platform.startswith("win"):
pytest.skip("skipping windows-only tests", allow_module_level=True)
如果您希望有條件地跳過某些內(nèi)容,則可以改用 ?skipif
?。 以下是在 Python3.10 之前的解釋器上運(yùn)行時標(biāo)記要跳過的測試函數(shù)的示例:
import sys
@pytest.mark.skipif(sys.version_info < (3, 10), reason="requires python3.10 or higher")
def test_function():
...
如果在收集過程中條件評估為 ?True
?,則將跳過測試函數(shù),使用 ?-rs
? 時會在摘要中顯示指定的原因。
您可以在模塊之間共享 ?skipif
標(biāo)記。 考慮這個測試模塊:
# content of test_mymodule.py
import mymodule
minversion = pytest.mark.skipif(
mymodule.__versioninfo__ < (1, 1), reason="at least mymodule-1.1 required"
)
@minversion
def test_function():
...
您可以導(dǎo)入標(biāo)記并在另一個測試模塊中重用它:
# test_myothermodule.py
from test_mymodule import minversion
@minversion
def test_anotherfunction():
...
對于較大的測試套件,最好使用一個文件來定義標(biāo)記,然后在整個測試套件中始終如一地應(yīng)用這些標(biāo)記。
或者,您可以使用條件字符串而不是布爾值,但它們不能在模塊之間輕松共享,因此主要出于向后兼容性的原因支持它們。
您可以在類上使用 ?skipif
標(biāo)記(與任何其他標(biāo)記一樣):
@pytest.mark.skipif(sys.platform == "win32", reason="does not run on windows")
class TestPosixCalls:
def test_function(self):
"will not be setup or run under 'win32' platform"
如果條件為?True
?,該標(biāo)記將為該類的每個測試方法產(chǎn)生一個跳過結(jié)果。
如果你想跳過一個模塊的所有測試函數(shù),你可以使用全局?pytestmark
?:
# test_module.py
pytestmark = pytest.mark.skipif(...)
如果將多個 ?skipif
?裝飾器應(yīng)用于測試函數(shù),則如果任何跳過條件為?true
?,它將被跳過。
有時您可能需要跳過整個文件或目錄,例如,如果測試依賴于 Python 版本特定的功能或包含您不希望 pytest 運(yùn)行的代碼。 在這種情況下,您必須從集合中排除文件和目錄。
您可以通過在模塊級別、測試或測試設(shè)置函數(shù)中使用 ?pytest.importorskip
? 來跳過缺少導(dǎo)入的測試。
docutils = pytest.importorskip("docutils")
如果此處無法導(dǎo)入 ?docutils
?,這將導(dǎo)致測試的跳過結(jié)果。 您也可以根據(jù)庫的版本號跳過:
docutils = pytest.importorskip("docutils", minversion="0.3")
版本將從指定模塊的 ?__version__
? 屬性中讀取。
以下是有關(guān)如何在不同情況下跳過模塊中的測試的快速指南:
pytestmark = pytest.mark.skip("all tests still WIP")
pytestmark = pytest.mark.skipif(sys.platform == "win32", reason="tests for linux only")
pexpect = pytest.importorskip("pexpect")
您可以使用 ?xfail
標(biāo)記來指示您希望測試失敗:
@pytest.mark.xfail
def test_function():
...
此測試將運(yùn)行,但失敗時不會報告回溯。 相反,終端報告會將其列在“預(yù)期失敗”(?XFAIL
?)或“意外通過”(?XPASS
?)部分。
或者,您也可以在測試或其設(shè)置函數(shù)中強(qiáng)制將測試標(biāo)記為 ?XFAIL
?:
def test_function():
if not valid_config():
pytest.xfail("failing configuration (but should work)")
def test_function2():
import slow_module
if slow_module.slow_function():
pytest.xfail("slow_module taking too long")
這兩個例子說明了您不希望在模塊級檢查條件的情況,也就是當(dāng)一個條件將被用于標(biāo)記時。
這將使?test_function XFAIL
?。請注意,在調(diào)用?pytest.xfail()
?之后不會執(zhí)行其他代碼,這與標(biāo)記不同。這是因?yàn)樗峭ㄟ^引發(fā)已知異常在內(nèi)部實(shí)現(xiàn)的。
如果測試只在特定條件下失敗,您可以將該條件作為第一個參數(shù)傳遞:
@pytest.mark.xfail(sys.platform == "win32", reason="bug in a 3rd party library")
def test_function():
...
你可以用?reason
?參數(shù)指定預(yù)期失敗的動機(jī):
@pytest.mark.xfail(reason="known parser issue")
def test_function():
...
如果您想更具體地了解測試失敗的原因,您可以在 ?raises
參數(shù)中指定單個異?;虍惓TM:
@pytest.mark.xfail(raises=RuntimeError)
def test_function():
...
然后,如果測試失敗并出現(xiàn) ?raises
中未提及的異常,則該測試將被報告為常規(guī)失敗。
如果測試應(yīng)標(biāo)記為 ?xfail
并報告為 ?xfail
?,但甚至不應(yīng)執(zhí)行,請將 ?run
?參數(shù)設(shè)置為 ?False
?:
@pytest.mark.xfail(run=False)
def test_function():
...
這對于導(dǎo)致解釋器崩潰的失敗測試特別有用,應(yīng)該稍后進(jìn)行調(diào)查。
默認(rèn)情況下,?XFAIL
和 ?XPASS
都不會使測試套件失敗。 您可以通過將 ?strict keyword-only
? 參數(shù)設(shè)置為 ?True
來更改此設(shè)置:
@pytest.mark.xfail(strict=True)
def test_function():
...
這將使該測試的 ?XPASS
?(“意外通過”)結(jié)果無法通過測試套件。
您可以使用 ?xfail_strict ini
? 選項(xiàng)更改 ?strict
參數(shù)的默認(rèn)值:
[pytest]
xfail_strict=true
通過在命令行上指定:
pytest --runxfail
您可以強(qiáng)制運(yùn)行和報告帶有 ?xfail
標(biāo)記的測試,就好像它根本沒有標(biāo)記一樣。 這也會導(dǎo)致 ?pytest.xfail()
? 不起作用。
例如,這是一個具有多種用途的簡單測試文件:
import pytest
xfail = pytest.mark.xfail
@xfail
def test_hello():
assert 0
@xfail(run=False)
def test_hello2():
assert 0
@xfail("hasattr(os, 'sep')")
def test_hello3():
assert 0
@xfail(reason="bug 110")
def test_hello4():
assert 0
@xfail('pytest.__version__[0] != "17"')
def test_hello5():
assert 0
def test_hello6():
pytest.xfail("reason")
@xfail(raises=IndexError)
def test_hello7():
x = []
x[1] = 1
使用 ?report-on-xfail
? 選項(xiàng)運(yùn)行它會給出以下輸出:
! pytest -rx xfail_demo.py
=========================== test session starts ============================
platform linux -- Python 3.x.y, pytest-6.x.y, py-1.x.y, pluggy-1.x.y
cachedir: $PYTHON_PREFIX/.pytest_cache
rootdir: $REGENDOC_TMPDIR/example
collected 7 items
xfail_demo.py xxxxxxx [100%]
========================= short test summary info ==========================
XFAIL xfail_demo.py::test_hello
XFAIL xfail_demo.py::test_hello2
reason: [NOTRUN]
XFAIL xfail_demo.py::test_hello3
condition: hasattr(os, 'sep')
XFAIL xfail_demo.py::test_hello4
bug 110
XFAIL xfail_demo.py::test_hello5
condition: pytest.__version__[0] != "17"
XFAIL xfail_demo.py::test_hello6
reason: reason
XFAIL xfail_demo.py::test_hello7
============================ 7 xfailed in 0.12s ============================
使用參數(shù)化時,可以將skip
和xfail
等標(biāo)記應(yīng)用于單個測試實(shí)例:
import sys
import pytest
@pytest.mark.parametrize(
("n", "expected"),
[
(1, 2),
pytest.param(1, 0, marks=pytest.mark.xfail),
pytest.param(1, 3, marks=pytest.mark.xfail(reason="some bug")),
(2, 3),
(3, 4),
(4, 5),
pytest.param(
10, 11, marks=pytest.mark.skipif(sys.version_info >= (3, 0), reason="py2k")
),
],
)
def test_increment(n, expected):
assert n + 1 == expected
更多建議: