Python assert 異常
這篇文章讓人們瞭解 assert
作為一個測試單元,以測試函式是否可以丟擲異常(程式碼執行期間檢測到的錯誤)而不必退出執行。換句話說,丟擲的異常被封裝了。
如果引發異常,則此測試將通過。如果丟擲不同於預期的異常,則會丟擲錯誤。在根本沒有引發異常的例項中,測試失敗。
使用上下文管理器捕獲 Python assert 異常
與通用 Python 概念中必要時允許分配和釋放資源的方式類似,這裡的上下文獲取測試期間丟擲的實際異常物件。
如果需要對引發的異常進行額外的效能檢查,它會將這個異常屬性儲存在物件中。
為了測試函式是否失敗或通過是否丟擲異常,我們將使用 unittest
模組中的 TestCase.assertRaises
。
讓我們看一個使用上下文管理器的實際示例。
import unittest
class TestCase(unittest.TestCase):
def test_nameerror(self):
with self.assertRaises(Exception):
100 * (someNumber / 5)
if __name__ == "__main__":
unittest.main()
輸出:
.
----------------------------------------------------------------------
Ran 1 test in 0.002s
OK
在示例程式碼中,測試通過是因為我們期望丟擲異常。我們將 5 除以未定義的變數 someNumber
。因此,該函式會引發 NameError
異常。因此,我們的測試通過了,你可以看到 .
顯示在輸出的第一行。
讓我們看一個例子,當沒有丟擲異常時測試失敗。
import unittest
class TestCase(unittest.TestCase):
def test_nameerror(self):
with self.assertRaises(Exception):
someNumber = 10
100 * (someNumber / 5)
if __name__ == "__main__":
unittest.main()
輸出:
F
======================================================================
FAIL: test_nameerror (__main__.MyTestCase)
----------------------------------------------------------------------
Traceback (most recent call last): File "c:\Users\Neema\Desktop\Article Requirement Spec and Example
Articles\Article Requirement Spec
and Example Articles\fah.py", line 106, in test_nameerror
100 * (someNumber/5)
AssertionError: Exception not raised
----------------------------------------------------------------------
Ran 1 test in 0.002s
FAILED (failures=1)
在此示例程式碼中,我們為 someNumber
定義了一個值,然後用它執行算術表示式。
輸出向我們顯示測試按預期失敗。我們不希望這次丟擲任何 NameError
異常,因為 someNumber
的定義值確實存在。
我們也可以使用使用者定義的異常來實現上下文管理器,如下例所示。
import unittest
def user_function():
raise Exception("A user-defined exception")
class MyTestCase(unittest.TestCase):
def test_userexception(self):
with self.assertRaises(Exception) as context:
user_function()
self.assertTrue("A user-defined exception" in str(context.exception))
if __name__ == "__main__":
unittest.main()
輸出:
.
----------------------------------------------------------------------
Ran 1 test in 0.006s
OK
請記住使用
str
將context.exception
括起來,以避免出現 TypeError。
我們引入了 assertTrue
,一個 unittest
庫,用於在單元測試中將測試值與 true 進行比較。
你還可以選擇使用 assertIn
而不是 assertTrue
。
例子:
import unittest
def user_function():
raise Exception("A use defined exception")
class MyTestCase(unittest.TestCase):
def test_userexception(self):
with self.assertRaises(Exception) as context:
user_function()
self.assertIn("A use defined exception", str(context.exception))
if __name__ == "__main__":
unittest.main()
我們看到將產生測試通過的相同輸出。
使用關鍵字引數捕獲 Python assert
異常
與上下文管理器不同,我們只將異常傳遞給 assertRaises()
,我們還將函式呼叫和函式引數作為關鍵字引數傳遞來引發異常。
語法
assertRaises(exception, function, *args, **keywords)
例子:
import unittest
class MyTestCase(unittest.TestCase):
def test_division_by_error(self):
import operator
self.assertRaises(ZeroDivisionError, operator.floordiv, 55, 0)
if __name__ == "__main__":
unittest.main()
輸出:
.
----------------------------------------------------------------------
Ran 1 test in 0.002s
OK
上面的示例程式碼使用帶有關鍵字引數的 assertRaises()
。在嘗試將數字除以零後,我們將預期的 ZeroDivisionError
異常傳遞給它。我們匯入了與 floordiv
運算子函式一起使用的運算子函式作為第二個引數。這裡的引數值是第三個引數:55 除以 0。
assert 的最後一個應用是當我們向 assertRaises() 傳入一個不同於預期的異常時。反而會產生錯誤。
使用我們剛剛在上面使用的相同示例程式碼,讓我們實現它。
import unittest
class MyTestCase(unittest.TestCase):
def test_division_by_error(self):
import operator
self.assertRaises(TypeError, operator.floordiv, 55, 0)
if __name__ == "__main__":
unittest.main()
輸出:
E
======================================================================
ERROR: test_division_by_error (__main__.MyTestCase)
----------------------------------------------------------------------
Traceback (most recent call last): File "c:\Users\Neema\Desktop\Article Requirement Spec and Example
Articles\user.py", line 16, in test_division_by_error
self.assertRaises(TypeError, operator.floordiv, 55, 0)
File "C:\Users\Neema\AppData\Local\Programs\Python\Python39\lib\unittest\case.py", line 733, in assertRaises
return context.handle('assertRaises', args, kwargs)
File "C:\Users\Neema\AppData\Local\Programs\Python\Python39\lib\unittest\case.py", line 201, in handle
callable_obj(*args, **kwargs)
ZeroDivisionError: integer division or modulo by zero
----------------------------------------------------------------------
Ran 1 test in 0.031s
FAILED (errors=1)
從輸出中,會產生一個錯誤回溯。當我們將一個數字除以零時,我們預計會出現 ZeroDivisionError 異常。相反,我們傳入一個 TypeError 異常,在不同資料型別之間執行算術運算時應用,比如字串和整數。