#python #python-unittest #suppress-warnings #doctest
Вопрос:
Мои тесты на Python открывают некоторые файлы, которые он никогда не закрывает. Это не вызывает никаких проблем; они автоматически закрываются при уничтожении объекта, и добавление логики для обеспечения их явного закрытия излишне усложнило бы мою документацию.
Однако, когда тесты выполняются внутри unittest
, они начинают выдавать ResourceWarning()
s, добавляя бесполезный шум к моим выводам.
Например, учитывая leak.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
Есть несколько способов очистить это внутри доктестов, но все они добавляют сложности, которые отвлекали бы от документации. Это включает в себя явные вызовы a.close()
, использование with open("test-file") as a:
(которое также помещает тестируемый вывод ниже with
блока) или прямое удаление предупреждений с помощью » warnings.simplefilter(«игнорировать»).
Как я могу запустить тесты, unittest
чтобы подавить ResourceWarning()
s, как doctest
это делает?
Ответ №1:
doctest
не подавляет эти предупреждения. unittest
это дает им возможность. Мы, вероятно, хотим unittest
включить их для наших более традиционных тестов, поэтому мы не хотим подавлять их глобально.
Я уже использую load_tests
, чтобы добавить unittest
тесты, так что у нас есть хорошее место для этого. Мы не можем просто позвонить warnings.filterwarnings()
напрямую load_tests
, так как фильтры сбрасываются перед запуском нашего теста. Мы можем использовать setUp
аргумент doctest.DocTestSuite
, чтобы предоставить функцию, которая выполнит эту работу за нас.
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
.
Тщательно указав, что фильтровать по категориям, сообщениям и модулям, это должно ограничить риск подавления разработанных предупреждений, но это не безрисково.