Pytest官方教程-04-斷言的編寫和報告

斷言的編寫和報告

使用assert語句進行斷言

pytest允許你使用標準的Pythonassert斷言語句來驗證測試中的期望結(jié)果和實際結(jié)果。 例如,你可以編寫以下內(nèi)容:

# test_assert1.py文件內(nèi)容 def f(): return 3 def test_function(): assert f() == 4

來斷言你的函數(shù)返回一個特定的值。 如果此斷言失敗,你將看到函數(shù)調(diào)用的返回值:

$ pytest test_assert1.py =========================== 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 1 item test_assert1.py F [100%] ================================= FAILURES ================================= ______________________________ test_function _______________________________

def test_function():

> assert f() == 4

E assert 3 == 4

E + where 3 = f()

test_assert1.py:5: AssertionError =========================

1 failed in 0.12 seconds =========================

pytest支持顯示常見的包括調(diào)用,屬性,比較以及二元和一元運算符子表達式的值 (參考:pytest執(zhí)行Python測試失敗報告示例)。 你可以在不使用繁瑣的Python慣用構(gòu)造樣板代碼的同時,不丟失斷言失敗的對比信息(內(nèi)省信息)。

當然,你也可以像下面所示,指定斷言失敗的返回消息:

assert a % 2 == 0, "值為奇數(shù),應為偶數(shù)"

這樣將不會斷言失敗對比信息(內(nèi)省信息),而只簡單地在追溯信息中顯示你指定的失敗返回信息。

有關斷言內(nèi)省的更多信息,請參閱高級斷言內(nèi)省。

異常斷言

你可以像如下所示,使用pytest.raises作為上下文管理器來進行異常斷言:

import pytest def test_zero_division(): with pytest.raises(ZeroDivisionError): 1 / 0

如果需要訪問實際的異常信息,你可以使用:

def test_recursion_depth():

with pytest.raises(RuntimeError) as excinfo:

def f():

f() f() assert 'maximum recursion' in str(excinfo.value)

excinfo是一個ExceptionInfo實例,它是實際異常的裝飾器。 其主要屬性有.type,.value及.traceback三種

版本3.0已修改

在上下文管理器中,你可以使用參數(shù)message來指定自定義失敗信息:

>>> with raises(ZeroDivisionError, message="Expecting ZeroDivisionError"): ... pass ... Failed: Expecting ZeroDivisionError

如果你想編寫適用于Python 2.4的測試代碼,你還可以使用其他兩種方法來測試預期的異常:

pytest.raises(ExpectedException, func, *args, **kwargs) pytest.raises(ExpectedException, "func(*args, **kwargs)")

兩者都可以對帶任意參數(shù)的函數(shù),斷言是否出現(xiàn)了期望的異常:ExpectedException。 即使沒有異常或出現(xiàn)了不同的異常,報告生成器也能輸出一些有用的斷言信息。

注意,也可以為pytest.mark.xfail指定一個“raises”參數(shù),當引發(fā)異常時標記用例失?。?br>

@pytest.mark.xfail(raises=IndexError)

def test_f():

f()

對于你在代碼中故意設置的異常,使用pytest.raises斷言更加好用,而將@ pytest.mark.xfail與check函數(shù)一起使用對于已知未修復或依賴中的bug會更好。

此外,上下文管理器表單接受match關鍵字參數(shù)來測試正則表達式匹配中的異常(如unittest中的TestCase.assertRaisesRegexp方法):

import pytest def myfunc():

raise ValueError("Exception 123 raised")

def test_match():

with pytest.raises(ValueError, match=r'.* 123 .*'): myfunc()

match變量后的正則表達式與使用re.search函數(shù)來進行匹配一致。 因此在上面的例子中,match ='123'不會引發(fā)異常。

警示斷言

2.8版本新增

你可以使用pytest.warns檢查代碼是否引發(fā)了特定警告。

使用上下文對比

2.0版本新增

pytest可以在斷言的比較中提供豐富的上下文信息。 例如:

# test_assert2.py文件內(nèi)容 def test_set_comparison():

set1 = set("1308")

set2 = set("8035")

assert set1 == set2

當你運行這個模塊后

$ pytest test_assert2.py =========================== 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 1 item test_assert2.py F [100%] ================================= FAILURES ================================= ___________________________ test_set_comparison ____________________________

def test_set_comparison():

set1 = set("1308")

set2 = set("8035")

> assert set1 == set2

E AssertionError: assert {'0', '1', '3', '8'} == {'0', '3', '5', '8'}

E Extra items in the left set:

E '1'

E Extra items in the right set:

E '5'

E Use -v to get the full diff test_assert2.py:5: AssertionError =========================

1 failed in 0.12 seconds =========================

對大量用例進行了特定對比:

長字符串斷言:顯示上下文差異

長序列斷言:顯示第一個失敗的索引

字典斷言:顯示不同的key-value對

有關更多示例,請參閱報告樣例。

自定義斷言對比信息

可以通過實現(xiàn)hook方法pytest_assertrepr_compare來在斷言結(jié)果中添加你自己的詳細說明信息。

pytest_assertrepr_compare(config, op, left, right)[源碼]

返回失敗斷言表達式中的對比信息。

如果沒有自定義對比信息,則返回None,否則返回一列字符串。 字符串將由換行符連接,但字符串中的任何換行符都將被轉(zhuǎn)義。 請注意,除第一行外的所有行都將略微縮進,目的是將第一行作為摘要。

參數(shù): config(pytest.config.Config* - pytest config 對象

例如,在conftest.py文件中添加以下鉤子方法,可以為Foo對象提供了附加對比信息:

# conftest.py內(nèi)容 from test_foocompare import Foo def pytest_assertrepr_compare(op, left, right): if isinstance(left, Foo) and isinstance(right, Foo) and op == "==": return ['Foo實例對比:', ' 值: %s != %s' % (left.val, right.val)]

現(xiàn)在,在測試模塊使用

# test_foocompare.py內(nèi)容 class Foo(object): def __init__(self, val): self.val = val def __eq__(self, other): return self.val == other.val def test_compare(): f1 = Foo(1) f2 = Foo(2) assert f1 == f2

運行這個測試模塊你可以看到conftest.py文件中定義的自定義輸出:

$ pytest -q test_foocompare.py

F

================================= FAILURES ================================= _______________________________ test_compare _______________________________

def test_compare():

f1 = Foo(1)

f2 = Foo(2)

> assert f1 == f2

E assert Foo實例對比:

E 值: 1 != 2

test_foocompare.py:11: AssertionError

1 failed in 0.12 seconds

高級斷言內(nèi)省

2.1版本新功能

報告有關失敗斷言的詳細信息是通過在運行之前重寫assert語句來實現(xiàn)的。 重寫的斷言語句將內(nèi)省信息放入斷言失敗消息中。pytest只重寫測試收集過程直接發(fā)現(xiàn)的測試模塊中的assert斷言,因此在支持模塊(非測試模塊)中的斷言,不會被重寫。

你可以在導入模塊前通過調(diào)用register_assert_rewrite手動啟用斷言重寫(比如可以在conftest.py這樣使用)。

注意

pytest通過使用導入hook方法寫入新的pyc文件來重寫測試模塊。 通常這種結(jié)構(gòu)比較清晰。 但是,如果你混亂導入,導入的hook方法可能會受到干擾。

如果是這種情況,您有兩種選擇:

通過將字符串PYTEST_DONT_REWRITE添加到其docstring來禁用特定模塊的重寫。

使用--assert = plain禁用所有模塊的重寫。

此外,如果無法寫入新的.pyc文件(如在只讀文件系統(tǒng)或zip文件中),重寫將無提示失敗。

有關進一步的信息,課參閱:本杰明彼得森寫的pytest的新斷言改寫的幕后故事。

版本2.1新功能:添加斷言重寫作為備用內(nèi)省技術。

版本2.1更改:引入--assert選項。 棄用--no-assert和--nomagic。

版本3.0版更改:刪除--no-assert和--nomagic選項。 刪除--assert = reinterp`選項。

老師微信:xiaowanzi02620[/cp]

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容