如何編寫一個unittest,只有在函數沒有拋出預期的異常時纔會失敗?你如何測試Python函數拋出異常?
回答
使用TestCase.assertRaises
(或TestCase.failUnlessRaises
)從單元測試模塊,例如:
import mymod
class MyTestCase(unittest.TestCase):
def test1(self):
self.assertRaises(SomeCoolException, mymod.myfunc)
看看unittest
模塊的assertRaises方法。
您的代碼應遵循此模式(這是一個單元測試模塊的風格測試):
def test_afunction_throws_exception(self):
try:
afunction()
except ExpectedException:
pass
except Exception as e:
self.fail('Unexpected exception raised:', e)
else:
self.fail('ExpectedException not raised')
關於Python < 2.7此構造對於檢查預期異常中的特定值很有用。單元測試功能assertRaises
僅檢查是否引發異常。
在我以前的答案的代碼可以簡化爲:
def test_afunction_throws_exception(self):
self.assertRaises(ExpectedException, afunction)
如果機能缺失接受參數,只需將它們傳遞到assertRaises這樣的:
def test_afunction_throws_exception(self):
self.assertRaises(ExpectedException, afunction, arg1, arg2)
如何處理控制檯中存在的異常的追蹤?也就是說,在其他方面通過的測試中有一個追溯。 – MadPhysicist 2017-03-15 14:13:13
@MadPhysicist我看不到你在說什麼。我剛剛在Python 2.6和3.5上進行了測試 - 沒有將Tracebacks打印到控制檯。也許你正在打印或記錄代碼中的回溯? – 2017-04-04 17:43:55
我用文檔測試 [1 ]幾乎無處不在,因爲我喜歡我同時記錄和測試我的功能的事實。
看一看這段代碼:
def throw_up(something, gowrong=False):
"""
>>> throw_up('Fish n Chips')
Traceback (most recent call last):
...
Exception: Fish n Chips
>>> throw_up('Fish n Chips', gowrong=True)
'I feel fine!'
"""
if gowrong:
return "I feel fine!"
raise Exception(something)
if __name__ == '__main__':
import doctest
doctest.testmod()
如果你把這個例子中的模塊中,並通過命令行測試案例進行評估,並檢查運行它。
[1] Python documentation: 23.2 doctest -- Test interactive Python examples
我剛剛發現Mock library提供assertRaisesWithMessage()方法(在它的子類unittest.TestCase生成),這將不僅檢查了預期的異常升高,而且它是與預期的消息提出:
from testcase import TestCase
import mymod
class MyTestCase(TestCase):
def test1(self):
self.assertRaisesWithMessage(SomeCoolException,
'expected message',
mymod.myfunc)
因爲Python 2.7,你可以使用上下文管理器來獲得拋出的實際Exception對象的保持:
import unittest
def broken_function():
raise Exception('This is broken')
class MyTestCase(unittest.TestCase):
def test(self):
with self.assertRaises(Exception) as context:
broken_function()
self.assertTrue('This is broken' in context.exception)
if __name__ == '__main__':
unittest.main()
http://docs.python.org/dev/library/unittest.html#unittest.TestCase.assertRaises
在的Python 3.5,你必須包裝在str
context.exception
,否則你會得到一個TypeError
self.assertTrue('This is broken' in str(context.exception))
您可以使用assertRaises從單元測試模塊
import unittest
class TestClass():
def raises_exception(self):
raise Exception("test")
class MyTestCase(unittest.TestCase):
def test_if_method_raises_correct_exception(self):
test_class = TestClass()
# note that you dont use() when passing the method to assertRaises
self.assertRaises(Exception, test_class.raises_exception)
來自:http://www.lengrand.fr/2011/12/pythonunittest-assertraises-raises-error/
首先,這裏是文件dum_function中相應的(仍然是dum:p)函數。潘岳:
def square_value(a):
"""
Returns the square value of a.
"""
try:
out = a*a
except TypeError:
raise TypeError("Input should be a string:")
return out
這裏是要進行的測試(僅適用於本次測試插入):
import dum_function as df # import function module
import unittest
class Test(unittest.TestCase):
"""
The class inherits from unittest
"""
def setUp(self):
"""
This method is called before each test
"""
self.false_int = "A"
def tearDown(self):
"""
This method is called after each test
"""
pass
#---
## TESTS
def test_square_value(self):
# assertRaises(excClass, callableObj) prototype
self.assertRaises(TypeError, df.square_value(self.false_int))
if __name__ == "__main__":
unittest.main()
現在我們可以測試我們的功能!以下是試圖運行測試時發生的情況:
======================================================================
ERROR: test_square_value (__main__.Test)
----------------------------------------------------------------------
Traceback (most recent call last):
File "test_dum_function.py", line 22, in test_square_value
self.assertRaises(TypeError, df.square_value(self.false_int))
File "/home/jlengrand/Desktop/function.py", line 8, in square_value
raise TypeError("Input should be a string:")
TypeError: Input should be a string:
----------------------------------------------------------------------
Ran 1 test in 0.000s
FAILED (errors=1)
TypeError被觸發,並生成測試失敗。問題是這正是我們想要的行爲:s。
爲了避免這種錯誤,只需在測試呼叫使用lambda運行函數:
self.assertRaises(TypeError, lambda: df.square_value(self.false_int))
最終輸出:
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK
完美!
...對我來說也是完美的!
Thansk很多朱利安·朗格朗蘭伯特先生
你可以建立自己的contextmanager
檢查是否異常升高。
import contextlib
@contextlib.contextmanager
def raises(exception):
try:
yield
except exception as e:
assert True
else:
assert False
然後你就可以使用raises
這樣的:
with raises(Exception):
print "Hola" # Calls assert False
with raises(Exception):
raise Exception # Calls assert True
如果使用的是pytest
,這件事情已經落實。你可以做pytest.raises(Exception)
:
例子:
def test_div_zero():
with pytest.raises(ZeroDivisionError):
1/0
而結果:
[email protected]$ py.test
================= test session starts =================
platform linux2 -- Python 2.6.6 -- py-1.4.20 -- pytest-2.5.2 -- /usr/bin/python
collected 1 items
tests/test_div_zero.py:6: test_div_zero PASSED
你如何測試一個Python函數拋出一個異常?
如何編寫一個測試,只有在函數不會將 預期的異常拋出時纔會失敗?
答案很簡單:
使用self.assertRaises
方法作爲上下文管理器:
def test_1_cannot_add_int_and_str(self):
with self.assertRaises(TypeError):
1 + '1'
示範
的最佳實踐方法是很容易在Python外殼來證明。
的unittest
庫
在Python 2。7或3:
import unittest
在Python 2.6,你可以安裝2.7的unittest
庫的反向移植,叫,只是別名爲unittest
:
import unittest2 as unittest
示例測試
現在,將Python的類型安全性粘貼到您的Python shell中:
class MyTestCase(unittest.TestCase):
def test_1_cannot_add_int_and_str(self):
with self.assertRaises(TypeError):
1 + '1'
def test_2_cannot_add_int_and_str(self):
import operator
self.assertRaises(TypeError, operator.add, 1, '1')
測試人員使用assertRaises
作爲上下文管理器,可確保在記錄時正確捕獲並清除錯誤。
我們也可以寫它沒有上下文管理器,見測試二。第一個參數是您期望提出的錯誤類型,第二個參數,您正在測試的函數,剩餘的參數和關鍵字參數將被傳遞給該函數。
我認爲它更簡單,更易讀,更易於使用上下文管理器。
運行測試
運行測試:
unittest.main(exit=False)
在Python 2.6,你可能會need the following:
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromTestCase(MyTestCase))
而且終端應該輸出如下:
..
----------------------------------------------------------------------
Ran 2 tests in 0.007s
OK
<unittest2.runner.TextTestResult run=2 errors=0 failures=0>
我們可以看到,正如我們預期的那樣,試圖在TypeError
中添加1
和'1'
。
更詳細的輸出,試試這個:
unittest.TextTestRunner(verbosity=2).run(unittest.TestLoader().loadTestsFromTestCase(MyTestCase))
- 1. 你如何測試函數拋出異常?
- 2. Python的 - 測試屬性拋出異常
- 3. 如何測試函數是否不拋出異常?
- 4. 如何測試異常拋出midje
- 5. 如何測試拋出異常
- 6. 如何測試沒有異常拋出?
- 7. Spock拋出異常測試
- 8. Python:你如何測試嵌套函數?
- 9. 測試失敗,因爲拋出異常
- 10. 的Arquillian測試拋出NoSuchElementException異常
- 11. mvn測試拋出空指針異常
- 12. 測試控制器拋出的異常
- 13. Mockito測試void方法拋出異常
- 14. 測試應該失敗拋出異常
- 15. Jasmine通過測試,拋出異常
- 16. .NET ComboBox.Items.Add(「測試值」)拋出異常
- 17. 如何檢測CLR拋出的異常?
- 18. C#:你提出或拋出異常?
- 19. 錯誤測試拋出的異常測試
- 20. 如何使用Python unittest assertRaises來測試該函數不會拋出任何異常?
- 21. 如何測試異常與Junit一起拋出
- 22. 我如何測試每條線都拋出相同的異常?
- 23. 如何測試特定異常是否不被拋出?
- 24. 如何在Android中測試斷言拋出異常
- 25. 如何測試Clojure中拋出的異常?
- 26. 如何在單元測試中模擬拋出異常?
- 27. 如何在本單元測試中拋出「N」異常?
- 28. Python單元測試:我如何測試異常中的參數?
- 29. 魔術異常拋出拋出異常
- 30. 拋出異常拋出異常
是有辦法做到這相反?就像它只有在函數拋出異常時纔會失敗? – BUInvent 2017-07-26 19:44:59
@BUInvent,是的,有:https://stackoverflow.com/a/4319870/3405140 – moertel 2017-07-27 16:23:47
請注意,要將參數傳遞給`myfunc`,您需要將它們作爲參數添加到assertRaises調用中。見Daryl Spitzer的回答。 – cbron 2018-02-21 16:43:15