你如何testing一个Python函数抛出一个exception?
如何编写一个unittest,只有当一个函数没有抛出预期的exception时才会失败?
使用unittest模块中的TestCase.assertRaises
(或TestCase.failUnlessRaises
),例如:
import mymod class MyTestCase(unittest.TestCase): def test1(self): self.assertRaises(SomeCoolException, mymod.myfunc)
从Python 2.7开始,您可以使用上下文pipe理器来获取抛出的实际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))
我以前的答案中的代码可以简化为:
def test_afunction_throws_exception(self): self.assertRaises(ExpectedException, afunction)
如果函数有参数,只需将它们传递给assertRaises就可以了:
def test_afunction_throws_exception(self): self.assertRaises(ExpectedException, afunction, arg1, arg2)
你如何testing一个Python函数抛出一个exception?
如何编写一个只有在函数不抛出预期exception的情况下才会失败的testing?
简答:
使用self.assertRaises
方法作为上下文pipe理器:
def test_1_cannot_add_int_and_str(self): with self.assertRaises(TypeError): 1 + '1'
示范
最佳实践方法在Python shell中很容易演示。
unit testing库
在Python 2.7或3中:
import unittest
在Python 2.6中,你可以安装一个名为unittest2的2.7unit testing库的backport,并且将其作为unit testing的别名:
import unittest2 as unittest
示例testing
现在,将Python的types安全性testing粘贴到您的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')
testing人员使用assertRaises
作为上下文pipe理器,确保在logging时正确捕获和清除错误。
我们也可以在没有上下文pipe理器的情况下编写它,参见testing二。 第一个参数是你期望提出的错误types,第二个参数,你正在testing的函数,其余的参数和关键字参数将被传递给该函数。
我认为它更简单,更易读,更易于使用上下文pipe理器。
运行testing
运行testing:
unittest.main(exit=False)
在Python 2.6中,您可能需要以下内容 :
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromTestCase(MyTestCase))
你的terminal应该输出以下内容:
.. ---------------------------------------------------------------------- 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))
你的代码应该遵循这个模式(这是一个unit testing模块风格testing):
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这个结构对检查预期exception中的特定值很有用。 unittest函数assertRaises
只检查是否引发exception。
我几乎在任何地方都使用doctest [1],因为我喜欢同时logging和testing我的function的事实。
看看这个代码:
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()
如果你把这个例子放在一个模块中并从命令行运行,那么这两个testing用例都将被评估和检查。
[1] Python文档:23.2 doctest – testing交互式Python示例
来自: http : //www.lengrand.fr/2011/12/pythonunittest-assertraises-raises-error/
首先,这里是文件dum_function.py中相应的(仍然是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
这里是要执行的testing(只有这个testing被插入):
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()
我们现在准备testing我们的function! 这是试图运行testing时发生的事情:
====================================================================== 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被动作提出,并产生一个testing失败。 问题是,这正是我们想要的行为:s。
为了避免这个错误,只需在testing调用中使用lambda来运行函数:
self.assertRaises(TypeError, lambda: df.square_value(self.false_int))
最终输出:
---------------------------------------------------------------------- Ran 1 test in 0.000s OK
完美!
…对我来说也是完美的!
Thansk很多Julien Lengrand-Lambert先生
看看unittest
模块的assertRaises方法。
我刚刚发现, Mock库提供了一个assertRaisesWithMessage()方法(在它的unittest.TestCase子类中),它不仅检查期望的exception是否被引发,而且还会引发预期的消息:
from testcase import TestCase import mymod class MyTestCase(TestCase): def test1(self): self.assertRaisesWithMessage(SomeCoolException, 'expected message', mymod.myfunc)
您可以构build自己的contextmanager
来检查是否引发exception。
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
结果是:
pigueiras@pigueiras$ 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
你可以使用unittest模块中的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)
- .Net处理exception时常见的编程错误?
- 在ASP.NET Web Api中捕获所有未处理的exception
- 如何防止后台线程中的exception终止应用程序?
- '+ entityForName:nil不是合法的NSManagedObjectContext参数 – 核心数据
- 如何从“需求”中拯救:没有这样的文件加载在ruby?
- Java – 在try / catch中执行try / catch是不好的做法吗?
- locking的对象是否locking,如果内部发生exception?
- 排除BadImageFormatExceptionexception
- 如何find在C ++中抛出exception?