[跟著官方文檔學pytest][三][學習筆記]
1.如何在測試中編寫和報告斷言
1.1.使用assert語句進行斷言
pytest允許使用標準Python斷言來驗證Python測試中的期望和值。 例如,可以編寫以下內容:
# content of test_assert1.py def f(): return 3 def test_function(): assert f() == 4
斷言函數返回某個值。如果此斷言失敗,將看到函數調用的返回值:
pytest支持顯示最常見的子表達式的值,包括調用、屬性、比較以及二元和一元運算符。(請參閱pytest的Python故障報告演示)。這允許在不丟失內省信息的情況下使用慣用的Python構造而無需樣板代碼。
但是,如果使用這樣的斷言指定消息:
assert a%2==0,"value was odd, should be even"
然后根本不會發生斷言自省,消息將簡單地顯示在回溯中。
1.2.關于預期異常的斷言
為了編寫有關引發異常的斷言,可以使用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。
可以將匹配關鍵字參數傳遞給上下文管理器,以測試正則表達式是否匹配異常的字符串表示(類似于unittest中的TestCase.assertRaisesRegex方法):
import pytest def myfunc(): raise ValueError("Exception 123 raised") def test_match(): with pytest.raises(ValueError,match=r".* 123 .*"): myfunc()
match方法的regexp參數與re.search函數匹配,因此在上面的示例中match='123’也可以正常工作。
pytest.raises()函數還有另一種形式,可以在其中傳遞一個函數,該函數將使用給定的*args和**kwargs執行,并斷言引發了給定的異常:
pytest.raises(ExpectedException, func, *args, **kwargs)
如果出現無異常或錯誤異常等故障,reporter將為你提供有用的輸出。
請注意,也可以為pytest.mark.xfail指定一個“raises”參數,它以更具體的方式檢查測試是否失敗,而不僅僅是引發任何異常:
@pytest.mark.xfail(raises=IndexError) def test_f(): f()
使用pytest.raises()對于你正在測試自己的代碼故意引發的異常的情況可能會更好,而使用帶有檢查功能的@pytest.mark.xfail可能更適合記錄未修復的錯誤(其中測試 描述“應該”發生什么)或依賴項中的錯誤。
1.3.關于預期警告的斷言
可以使用pytest.warns檢查代碼是否引發特定警告。
1.4.利用上下文相關的比較
pytest對在遇到比較時提供上下文相關信息提供了豐富的支持。例如:
# content of test_assert4.py def test_set_comparison(): set1 = set("1308") set2 = set("8035") assert set1 == set2
輸出結果:
對許多情況進行了特殊比較:
比較長字符串:顯示上下文差異
比較長序列:第一個失敗的索引
比較字典:不同的條目
1.5.為失敗的斷言定義你自己的解釋
可以通過實現pytest_assertrepr_compare鉤子來添加自己的詳細說明。
pytest_assertrepr_compare(config, op, left, right)
返回失敗斷言表達式中比較的說明。 返回None表示沒有自定義說明,否則返回字符串列表。字符串將由換行符連接,但字符串中的任何換行符都將被轉義。請注意,除第一行外,其他所有行都將略微縮進,目的是將第一行作為摘要。 參數:config(pytest.Config)-pytest配置對象 op(str) left(object) right(object) 返回類型: Optional[List[str]]
例如,考慮在conftest.py文件中添加以下鉤子,該文件為Foo對象提供了替代說明:
# content of conftest.py from test_foocompare import Foo def pytest_assertrepr_compare(op, left, right): if isinstance(left, Foo) and isinstance(right, Foo) and op == "==": return [ "Comparing Foo instances:", " vals: {}!={}".format(left.val, right.val), ]
# content of test_foocompare.py class Foo: 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
輸出結果:
1.6.斷言內省詳細信息
有關失敗斷言的報告詳細信息是通過在運行斷言語句之前重寫斷言語句來實現的。重寫的斷言語句將自檢信息放入斷言失敗消息中。pytest =僅重寫其測試收集過程直接發現的測試模塊,因此不會重寫本身不是測試模塊的支持模塊中的斷言。
可以通過在導入導入模塊之前調用register_assert_rewrite來手動啟用斷言重寫(執行此操作的一個好位置是在conftest.py中)。
1.6.1.斷言重寫磁盤上的緩存文件
pytest會將重寫的模塊寫回磁盤進行緩存。可以通過將以下內容添加到conftest.py文件的頂部來禁用此行為(例如,避免在經常移動文件的項目中留下過時的.pyc文件):
import sys sys.dont_write_bytecode=True
請注意,你仍然可以獲得斷言自省的好處,唯一的更改是.pyc文件不會緩存在磁盤上。
此外,如果重寫無法寫入新的.pyc文件(即在只讀文件系統或zip文件中),則重寫將以靜默方式跳過緩存。
1.6.2.禁用斷言重寫
pytest通過使用導入鉤子編寫新的pyc文件,在導入時重寫測試模塊。大多數時候,這是透明的。但是,如果你自己使用導入機器,則導入鉤子可能會干擾。
如果是這種情況,你有兩種選擇:
通過將字符串PYTEST_DONT_REWRITE添加到特定模塊的文檔字符串來禁用其重寫。
使用–assert=plain禁用所有模塊的重寫。
Python
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。