您可以標(biāo)記不能在某些平臺(tái)上運(yùn)行的測(cè)試函數(shù),或者您預(yù)計(jì)會(huì)失敗的測(cè)試函數(shù),以便pytest可以相應(yīng)地處理它們,并顯示測(cè)試會(huì)話的摘要,同時(shí)保持測(cè)試套件為綠色。
?skip
?意味著您希望您的測(cè)試只有在滿足某些條件時(shí)才會(huì)通過,否則pytest應(yīng)該完全跳過運(yùn)行測(cè)試。常見的例子是跳過非windows平臺(tái)上的僅限windows的測(cè)試,或者跳過依賴于當(dāng)前不可用的外部資源(例如數(shù)據(jù)庫(kù))的測(cè)試。
?xfail
?意味著您預(yù)期測(cè)試由于某種原因會(huì)失敗。一個(gè)常見的例子是對(duì)尚未實(shí)現(xiàn)的特性或尚未修復(fù)的bug進(jìn)行測(cè)試。當(dāng)測(cè)試通過時(shí),盡管預(yù)期會(huì)失敗(標(biāo)記為?pytest.mark.xfail
?),它是一個(gè)?xpass
?,并將在測(cè)試總結(jié)中報(bào)告。
Pytest分別計(jì)數(shù)和列出?skip
?和?xfail
?測(cè)試。默認(rèn)情況下,不顯示有關(guān)?skip
?/?xfailed
?測(cè)試的詳細(xì)信息,以避免輸出混亂。你可以使用?-r
?選項(xiàng)來(lái)查看測(cè)試進(jìn)度中顯示的?short
?字母對(duì)應(yīng)的詳細(xì)信息:
pytest -rxXs # show extra info on xfailed, xpassed, and skipped tests
通過運(yùn)行 ?pytest -h
? 可以找到有關(guān) ?-r
選項(xiàng)的更多詳細(xì)信息。
跳過一個(gè)測(cè)試函數(shù)的最簡(jiǎn)單的方法是用?skip
?裝飾器來(lái)標(biāo)記它,它可以傳遞一個(gè)可選的原因:
@pytest.mark.skip(reason="no way of currently testing this")
def test_the_unknown():
...
或者,也可以通過調(diào)用 ?pytest.skip(reason)
? 函數(shù)在測(cè)試執(zhí)行或設(shè)置期間強(qiáng)制跳過:
def test_function():
if not valid_config():
pytest.skip("unsupported configuration")
當(dāng)在導(dǎo)入期間無(wú)法評(píng)估跳過條件時(shí),命令式方法很有用。
也可以在模塊級(jí)別使用 ?pytest.skip(reason, allow_module_level=True)
? 跳過整個(gè)模塊:
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)行時(shí)標(biāo)記要跳過的測(cè)試函數(shù)的示例:
import sys
@pytest.mark.skipif(sys.version_info < (3, 10), reason="requires python3.10 or higher")
def test_function():
...
如果在收集過程中條件評(píng)估為 ?True
?,則將跳過測(cè)試函數(shù),使用 ?-rs
? 時(shí)會(huì)在摘要中顯示指定的原因。
您可以在模塊之間共享 ?skipif
標(biāo)記。 考慮這個(gè)測(cè)試模塊:
# 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)記并在另一個(gè)測(cè)試模塊中重用它:
# test_myothermodule.py
from test_mymodule import minversion
@minversion
def test_anotherfunction():
...
對(duì)于較大的測(cè)試套件,最好使用一個(gè)文件來(lái)定義標(biāo)記,然后在整個(gè)測(cè)試套件中始終如一地應(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)記將為該類的每個(gè)測(cè)試方法產(chǎn)生一個(gè)跳過結(jié)果。
如果你想跳過一個(gè)模塊的所有測(cè)試函數(shù),你可以使用全局?pytestmark
?:
# test_module.py
pytestmark = pytest.mark.skipif(...)
如果將多個(gè) ?skipif
?裝飾器應(yīng)用于測(cè)試函數(shù),則如果任何跳過條件為?true
?,它將被跳過。
有時(shí)您可能需要跳過整個(gè)文件或目錄,例如,如果測(cè)試依賴于 Python 版本特定的功能或包含您不希望 pytest 運(yùn)行的代碼。 在這種情況下,您必須從集合中排除文件和目錄。
您可以通過在模塊級(jí)別、測(cè)試或測(cè)試設(shè)置函數(shù)中使用 ?pytest.importorskip
? 來(lái)跳過缺少導(dǎo)入的測(cè)試。
docutils = pytest.importorskip("docutils")
如果此處無(wú)法導(dǎo)入 ?docutils
?,這將導(dǎo)致測(cè)試的跳過結(jié)果。 您也可以根據(jù)庫(kù)的版本號(hào)跳過:
docutils = pytest.importorskip("docutils", minversion="0.3")
版本將從指定模塊的 ?__version__
? 屬性中讀取。
以下是有關(guān)如何在不同情況下跳過模塊中的測(cè)試的快速指南:
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)記來(lái)指示您希望測(cè)試失敗:
@pytest.mark.xfail
def test_function():
...
此測(cè)試將運(yùn)行,但失敗時(shí)不會(huì)報(bào)告回溯。 相反,終端報(bào)告會(huì)將其列在“預(yù)期失敗”(?XFAIL
?)或“意外通過”(?XPASS
?)部分。
或者,您也可以在測(cè)試或其設(shè)置函數(shù)中強(qiáng)制將測(cè)試標(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")
這兩個(gè)例子說(shuō)明了您不希望在模塊級(jí)檢查條件的情況,也就是當(dāng)一個(gè)條件將被用于標(biāo)記時(shí)。
這將使?test_function XFAIL
?。請(qǐng)注意,在調(diào)用?pytest.xfail()
?之后不會(huì)執(zhí)行其他代碼,這與標(biāo)記不同。這是因?yàn)樗峭ㄟ^引發(fā)已知異常在內(nèi)部實(shí)現(xiàn)的。
如果測(cè)試只在特定條件下失敗,您可以將該條件作為第一個(gè)參數(shù)傳遞:
@pytest.mark.xfail(sys.platform == "win32", reason="bug in a 3rd party library")
def test_function():
...
你可以用?reason
?參數(shù)指定預(yù)期失敗的動(dòng)機(jī):
@pytest.mark.xfail(reason="known parser issue")
def test_function():
...
如果您想更具體地了解測(cè)試失敗的原因,您可以在 ?raises
參數(shù)中指定單個(gè)異?;虍惓TM:
@pytest.mark.xfail(raises=RuntimeError)
def test_function():
...
然后,如果測(cè)試失敗并出現(xiàn) ?raises
中未提及的異常,則該測(cè)試將被報(bào)告為常規(guī)失敗。
如果測(cè)試應(yīng)標(biāo)記為 ?xfail
并報(bào)告為 ?xfail
?,但甚至不應(yīng)執(zhí)行,請(qǐng)將 ?run
?參數(shù)設(shè)置為 ?False
?:
@pytest.mark.xfail(run=False)
def test_function():
...
這對(duì)于導(dǎo)致解釋器崩潰的失敗測(cè)試特別有用,應(yīng)該稍后進(jìn)行調(diào)查。
默認(rèn)情況下,?XFAIL
和 ?XPASS
都不會(huì)使測(cè)試套件失敗。 您可以通過將 ?strict keyword-only
? 參數(shù)設(shè)置為 ?True
來(lái)更改此設(shè)置:
@pytest.mark.xfail(strict=True)
def test_function():
...
這將使該測(cè)試的 ?XPASS
?(“意外通過”)結(jié)果無(wú)法通過測(cè)試套件。
您可以使用 ?xfail_strict ini
? 選項(xiàng)更改 ?strict
參數(shù)的默認(rèn)值:
[pytest]
xfail_strict=true
通過在命令行上指定:
pytest --runxfail
您可以強(qiáng)制運(yùn)行和報(bào)告帶有 ?xfail
標(biāo)記的測(cè)試,就好像它根本沒有標(biāo)記一樣。 這也會(huì)導(dǎo)致 ?pytest.xfail()
? 不起作用。
例如,這是一個(gè)具有多種用途的簡(jiǎn)單測(cè)試文件:
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)行它會(huì)給出以下輸出:
! 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ù)化時(shí),可以將skip
和xfail
等標(biāo)記應(yīng)用于單個(gè)測(cè)試實(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
更多建議: