如何编写只有在函数没有抛出预期异常时才会失败的单元测试呢?


当前回答

对于await/async aiounittest有一个稍微不同的模式:

https://aiounittest.readthedocs.io/en/latest/asynctestcase.html#aiounittest.AsyncTestCase

async def test_await_async_fail(self):
    with self.assertRaises(Exception) as e:
        await async_one()

其他回答

对于await/async aiounittest有一个稍微不同的模式:

https://aiounittest.readthedocs.io/en/latest/asynctestcase.html#aiounittest.AsyncTestCase

async def test_await_async_fail(self):
    with self.assertRaises(Exception) as e:
        await async_one()

如果在这个类中将stock_id设置为Integer将抛出错误,则将引发TypeError,如果发生这种情况,则测试将通过,否则将失败

def set_string(prop, value):
   if not isinstance(value, str):
      raise TypeError("i told you i take strings only ")
   return value

class BuyVolume(ndb.Model):
    stock_id = ndb.StringProperty(validator=set_string)

from pytest import raises
buy_volume_instance: BuyVolume = BuyVolume()
with raises(TypeError):
  buy_volume_instance.stock_id = 25

从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

下面是要执行的测试(只插入这个测试):

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

完美!

... 对我来说也是完美的!!

非常感谢,Julien Lengrand-Lambert先生。


这个测试断言实际上返回一个假阳性。这是因为'assertRaises'中的lambda是引发类型错误的单元,而不是被测试的函数。

如何测试Python函数是否抛出异常? 如何编写只有在函数不抛出时才会失败的测试呢 意料之中的例外?

简短的回答:

利用自我。assertRaises方法作为上下文管理器:

    def test_1_cannot_add_int_and_str(self):
        with self.assertRaises(TypeError):
            1 + '1'

示范

在Python shell中很容易演示最佳实践方法。

unittest库

在Python 2.7或3中:

import unittest

在Python 2.6中,你可以安装2.7的unittest库的backport,称为unittest2,并将其别名为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作为上下文管理器,以确保在记录错误的同时正确地捕获和清除错误。

我们也可以在没有上下文管理器的情况下编写它,参见测试二。第一个参数是您期望引发的错误类型,第二个参数是您正在测试的函数,其余的args和关键字args将被传递给该函数。

我认为仅仅使用上下文管理器要简单得多,可读性和可维护性更强。

运行测试

要运行测试:

unittest.main(exit=False)

在Python 2.6中,您可能需要以下内容:

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))

使用TestCase。从unittest模块中assertRaises(或testcase . failunlessraised),例如:

import mymod

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