如何使用Python的unittest测试是否抛出了警告?

87 投票
7 回答
35510 浏览
提问于 2025-04-16 05:12

我在Python里有一个函数,我想用unittest来测试一下,如果这个函数接收到0作为参数,它会不会发出警告。我之前试过用assertRaises,但是因为我并没有主动抛出警告,所以这个方法不管用。

def isZero(i):
    if i != 0:
        print "OK"
    else:
        warning = Warning("the input is 0!") 
        print warning
    return i

7 个回答

18

你可以自己写一个叫做 assertWarns 的函数,来封装 catch_warnings 的上下文。我是这样实现的,使用了一个混合类:

class WarningTestMixin(object):
    'A test which checks if the specified warning was raised'

    def assertWarns(self, warning, callable, *args, **kwds):
        with warnings.catch_warnings(record=True) as warning_list:
            warnings.simplefilter('always')

            result = callable(*args, **kwds)

            self.assertTrue(any(item.category == warning for item in warning_list))

下面是一个使用示例:

class SomeTest(WarningTestMixin, TestCase):
    'Your testcase'

    def test_something(self):
        self.assertWarns(
            UserWarning,
            your_function_which_issues_a_warning,
            5, 10, 'john', # args
            foo='bar'      # kwargs
        )

如果 your_function 发出的警告中至少有一个是 UserWarning 类型,那么这个测试就会通过。

94

从Python 3.2开始,你可以直接使用assertWarns()这个方法。

with self.assertWarns(Warning):
    do_something()
63

你可以使用 catch_warnings 这个上下文管理器。简单来说,它可以让你模拟警告处理器,这样你就可以检查警告的具体内容。想要更详细的解释和示例代码,可以查看 官方文档

import warnings

def fxn():
    warnings.warn("deprecated", DeprecationWarning)

with warnings.catch_warnings(record=True) as w:
    # Cause all warnings to always be triggered.
    warnings.simplefilter("always")
    # Trigger a warning.
    fxn()
    # Verify some things
    assert len(w) == 1
    assert issubclass(w[-1].category, DeprecationWarning)
    assert "deprecated" in str(w[-1].message)

撰写回答