如何在单元测试下运行的 doctest 中抑制 ResourceWarning()s

问题描述

我的 Python doctests 打开了一些它从不关闭文件。这不会造成任何问题;当对象被销毁时它们会自动关闭,并且添加逻辑以确保它们被明确关闭会不必要地使我的文档复杂化。

然而,当 doctest 在 unittest 内运行时,它们开始发出 ResourceWarning(),给我的输出添加无益的噪音。

例如,给定的leaks.py:

def hello(f):
    """ 
    >>> a = open("test-file","w")
    >>> hello(a)
    >>> open("test-file").read()
    'hello'
    """
    f.write("hello")
    f.flush()

def load_tests(loader,tests,ignore):
    import doctest
    tests.addTests(doctest.DocTestSuite())
    return tests

在 doctest 和 unittest 下使用 Python 3.6.9 运行它会生成

$ python3 --version
Python 3.6.9
$ python3 -m doctest leak.py -v
[...] 
3 passed and 0 Failed.
Test passed.
$ python3 -m unittest leak
/tmp/fileleak/leak.py:1: ResourceWarning: unclosed file <_io.TextIOWrapper name='test-file' mode='r' encoding='UTF-8'>
  def hello(f):
/usr/lib/python3.6/doctest.py:2175: ResourceWarning: unclosed file <_io.TextIOWrapper name='test-file' mode='w' encoding='UTF-8'>
  test.globs.clear()
.
----------------------------------------------------------------------
Ran 1 test in 0.003s

OK

有几种方法可以在 doctests 中清理它,但它们都增加了复杂性,会分散文档中的注意力。这包括使用 a.close()with open("test-file") as a: 的显式调用(它还将测试的输出推送到 with 块下方,或者使用 `warnings.simplefilter("ignore") 直接丢弃警告。>

如何让 doctest 在 unittest 下运行以抑制 ResourceWarning()doctest 那样?

解决方法

doctest 没有抑制这些警告。 unittest 是 启用它们。我们可能希望 unittest 为我们更多地启用它们 传统的单元测试,所以我们不想全局抑制这些。

我已经在使用 load_tests 将 doctest 添加到 unittest,所以我们有 放置它的好地方。我们不能直接调用 warnings.filterwarnings()load_tests 中,因为在我们的测试运行之前过滤器已重置。我们可以使用 doctest.DocTestSuitesetUp 参数提供一个函数来为我们完成工作。

def load_tests(loader,tests,ignore):
    import doctest
    import warnings
    def setup(doc_test_obj):
        for module in (__name__,'doctest'):
            warnings.filterwarnings("ignore",message= r'unclosed file <_io.TextIOWrapper',category=ResourceWarning,module=module+"$")
    tests.addTests(doctest.DocTestSuite(setUp=setup))
    return tests

在我们创建的对象可能被破坏的任何地方,我们都需要过滤器 ResourceWarning 生成。这包括我们自己的模块 (__name__),但它 还包括 doctest 因为一些全局变量直到 DocTestCase.tearDown

通过仔细指定按类别、消息和模块过滤的内容,这 应该限制​​抑制设计警告的风险,但并非没有风险。