2008-09-24 102 views

回答

379

使用TestCase.assertRaises(或TestCase.failUnlessRaises)從單元測試模塊,例如:

import mymod 

class MyTestCase(unittest.TestCase): 
    def test1(self): 
     self.assertRaises(SomeCoolException, mymod.myfunc) 
+1

是有辦法做到這相反?就像它只有在函數拋出異常時纔會失敗? – BUInvent 2017-07-26 19:44:59

+4

@BUInvent,是的,有:https://stackoverflow.com/a/4319870/3405140 – moertel 2017-07-27 16:23:47

+0

請注意,要將參數傳遞給`myfunc`,您需要將它們作爲參數添加到assertRaises調用中。見Daryl Spitzer的回答。 – cbron 2018-02-21 16:43:15

24

您的代碼應遵循此模式(這是一個單元測試模塊的風格測試):

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僅檢查是否引發異常。

+2

和方法self.fail只帶一個參數 – mdob 2012-10-14 21:54:33

+3

這對於測試函數是否引發異常似乎過於複雜。由於除了那個異常之外的任何異常都會錯誤地測試,並且不會拋出異常將會使測試失敗,似乎唯一的區別是,如果你通過`assertRaises`得到一個不同的異常,你將得到一個ERROR而不是一個FAIL。 – unflores 2015-01-21 12:52:28

160

在我以前的答案的代碼可以簡化爲:

def test_afunction_throws_exception(self): 
    self.assertRaises(ExpectedException, afunction) 

如果機能缺失接受參數,只需將它們傳遞到assertRaises這樣的:

def test_afunction_throws_exception(self): 
    self.assertRaises(ExpectedException, afunction, arg1, arg2) 
+0

如何處理控制檯中存在的異常的追蹤?也就是說,在其他方面通過的測試中有一個追溯。 – MadPhysicist 2017-03-15 14:13:13

+0

@MadPhysicist我看不到你在說什麼。我剛剛在Python 2.6和3.5上進行了測試 - 沒有將Tracebacks打印到控制檯。也許你正在打印或記錄代碼中的回溯? – 2017-04-04 17:43:55

7

我用文檔測試 [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

4

我剛剛發現Mock library提供assertRaisesWithMessage()方法(在它的子類unittest.TestCase生成),這將不僅檢查了預期的異常升高,而且它是與預期的消息提出:

from testcase import TestCase 

import mymod 

class MyTestCase(TestCase): 
    def test1(self): 
     self.assertRaisesWithMessage(SomeCoolException, 
            'expected message', 
            mymod.myfunc) 
255

因爲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,你必須包裝在strcontext.exception,否則你會得到一個TypeError

self.assertTrue('This is broken' in str(context.exception)) 
0

您可以使用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) 
7

來自: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很多朱利安·朗格朗蘭伯特先生

2

你可以建立自己的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 
73

你如何測試一個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))