[英]Use a custom failure message for `assertRaises()` in Python?
所有斷言方法(除了
assertRaises()
、assertRaisesRegexp()
)都接受一個msg
參數,如果指定,則用作失敗時的錯誤消息
…但是如果我想為assertRaises()
或assertRaisesRegexp()
指定錯誤消息怎么辦?
用例:在循環中測試各種值時,如果一個失敗,我想知道是哪個:
NON_INTEGERS = [0.21, 1.5, 23.462, math.pi]
class FactorizerTestCase(unittest.TestCase):
def test_exception_raised_for_non_integers(self):
for value in NON_INTEGERS:
with self.assertRaises(ValueError):
factorize(value)
如果其中任何一個失敗,我會得到:
AssertionError: ValueError not raised
這對我找出哪個失敗沒有太大幫助……如果我能像assertEqual()
等一樣提供一個msg=
參數就好了!
(我當然可以將它們分解成單獨的測試函數——但也許有很多我想測試的值,或者它需要一些緩慢/昂貴的設置,或者它是更長的功能測試的一部分)
如果我可以輕松地讓它報告類似以下內容,我會很高興:
AssertionError: ValueError not raised for input 23.462
— 但它也不是一個足夠重要的事情來保證重新實現/擴展assertRaises()
並向我的測試添加更多代碼。
你也可以回self.fail
使用self.fail
這感覺很煩人,但我認為看起來有點不那么hacky
for value in NON_INTEGERS:
with self.assertRaises(ValueError) as cm:
factorize(value)
self.fail('ValueError not raised for {}'.format(value))
1.我發現最容易(但很笨拙!)這樣做的方法是:
for value in NON_INTEGERS:
with self.assertRaises(ValueError) as cm:
cm.expected.__name__ = 'ValueError for {}'.format(value) # custom failure msg
factorize(value)
將在失敗時報告此情況:
AssertionError: ValueError for 23.462 not raised
請注意,這僅在使用with …
語法時有效 。
它的工作原理是因為assertRaises()
上下文管理器在內部執行此操作:
exc_name = self.expected.__name__
…
raise self.failureException(
"{0} not raised".format(exc_name))
如果實現發生變化 ,那么可能會出現片狀 ,盡管Py3源代碼足夠相似,它也應該在那里工作(但不能說我已經嘗試過了)。
2. 不依賴於實現的最簡單方法是捕獲錯誤並使用改進的消息重新提升它:
for value in NON_INTEGERS:
try:
with self.assertRaises(ValueError) as cm:
factorize(value)
except AssertionError as e:
raise self.failureException('{} for {}'.format(e.message, value)), sys.exc_info()[2]
sys.exc_info()[2]
位用於重用原始堆棧跟蹤 ,但此語法僅為Py2 。 這個答案解釋了如何為Py3做這個(並啟發了這個解決方案)。
但這已經讓測試難以閱讀,所以我更喜歡第一種選擇。
“正確”的解決方案需要編寫assertRaises
和_AssertRaisesContext
類的包裝版本,當你遇到失敗時,你可能會拋出一些日志記錄,這聽起來有些過分。
在 Python 3 中, unittest
現在將錯誤消息公開為您with self.assertRaises()
從中獲取的_AssertRaisesContext
實例的一個適當的、可公開訪問的屬性。 所以在Python 3中,可以這樣做:
with self.assertRaises(ValueError) as assertion:
assertion.msg = f"ValueError not raised for input {value}"
factorize(value)
我使用它而不是assertRaises
:
def test_empty_username(self):
# noinspection PyBroadException
try:
my_func(username="")
except Exception:
# If it does, we are OK.
return
# If not, we are here.
self.fail("my_func() must reject empty username.")
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.