'unittest.TestCase“使全局”warnings.filterwarnings“过时

`unittest.TestCase` makes global `warnings.filterwarnings` obsolete

提问人:SchEma 提问时间:9/21/2023 最后编辑:SchEma 更新时间:9/22/2023 访问量:52

问:

我有一个模块,其中包含一些方法,这些方法确实会引发大量警告。 碰巧的是,警告是由外部模块引发的。在给定的上下文中,它们并不是真正有用,但它们的丰富性非常烦人。

为了抑制警告,我打算使用该方法。因为它们无处不在,所以我决定一劳永逸地抑制它们,即在模块级别,而不是由上下文管理器一次又一次地抑制它们。 不是很优雅,但它可以解决问题。warnings.filterwarningscatch_warnings

只是 - 它不能在 中起作用,在这种抑制被简单地忽略的情况下。我发现,在初始化和运行实际之间的一段时间内,在过滤器列表的前面插入了几个过滤器,其中,这使得后面的模块插入过滤器变得无用。unittest.TestCaseTestCasetest_method('default', None, <class 'Warning'>, None, 0)

现在的问题是:我怎样才能规避这个“功能”,并在测试中抑制警告?

MRE的

do.py:

import warnings

warnings.filterwarnings(
    action='ignore',
    message='boring',
)


def main():
    warnings.warn('boring')
    warnings.warn('interesting')


if __name__ == '__main__':
    main()

python do.py只产生“有趣”的东西。

test.py:

from unittest import TestCase
import warnings

import do


class DoTest(TestCase):

    def test_do(self):
        with warnings.catch_warnings(record=True) as ws:
            do.main()
        self.assertTrue([ w for w in ws if 'interesting' in w.message.args ])
        self.assertFalse([ w for w in ws if 'boring' in w.message.args ])

python -m unittest测试失败,并显示以下堆栈跟踪:

File "../test.py", line 13, in test_do
    self.assertFalse([ w for w in ws if 'boring' in w.message.args ])
AssertionError: [<warnings.WarningMessage object at 0x000001EE01A2D220>] is not false```


警告 python-unittest

评论


答:

0赞 Danila Ganchar 9/21/2023 #1

这里有 2 个示例:

from unittest import TestCase, mock
from unittest.mock import Mock

from do import main


# mock warnings for all class tests
class DoTest(TestCase):
    WARNING_MOCK = mock.patch('warnings.warn', return_value=Mock())

    @classmethod
    def setUpClass(cls) -> None:
        cls.WARNING_MOCK.start()  # disable warnings before tests

    @classmethod
    def tearDownClass(cls) -> None:
        cls.WARNING_MOCK.stop()  # enable warnings after tests

    def test_do(self):
        main()


# or using 'with' statement to call a context manager
# in this case you'll mock warnings only for specific test
class DoTest2(TestCase):
    def test_do(self):
        with mock.patch('warnings.warn', return_value=Mock()):
            main()

让我们检查一下:python -m unittest test

..
----------------------------------------------------------------------
Ran 2 tests in 0.002s

OK

评论

0赞 SchEma 9/22/2023
谢谢!有趣的方法,但这抑制了所有警告,我实际上需要在单元测试期间提供有趣的东西(我已经在这方面编辑原始问题)。此外,我希望有一个“一劳永逸”的解决方案,不愿意编辑所有受影响的测试文件。(请参阅我在主要;)中的赞美。
0赞 Danila Ganchar 9/22/2023
@SchEma JFYI:您不需要修改所有测试。您可以创建 1 个基本测试类并从中继承。或者在测试执行之前设置某个位置。mock
0赞 Danila Ganchar 9/22/2023
我见过类似的问题。也许我只是不明白。看起来人们正在尝试为 a 或包编写测试。你能解释一下你正在解决什么问题吗?loggingwarning
0赞 SchEma 9/24/2023
是的,我可以创建自己的派生类来继承,但我仍然需要更新所有测试模块。我试图解决的问题是,我的单元测试的控制台输出非常大,以至于在包含任何人类可读的有用信息之前必须对其进行进一步处理。是的,当然,我正在测试应用程序的日志记录和警告。其中一些至关重要。TestCase
0赞 Danila Ganchar 9/24/2023
我知道其中一些至关重要。我不明白这个问题。 意志有效。这只是事实。这意味着如果你调用它,它就可以工作。这不是你的/.你会为过滤器read_csv编写测试吗?不。因为它根本没有意义。但是你可以这样做,并为测试准备数据。logging.{SOMETHING}packagemodulemock