Документация Python неофициальный перевод

test.md

302 строк · 29.1 КБ · обычная страница · сырой текст · скачать

1> **Источник:** https://python-all.ru/3.2/library/test.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# 25.5. [`test`](https://python-all.ru/3.2/library/test.html#module-test) – Пакет регрессионных тестов для Python89> **Примечание**10>11> Пакет [`test`](https://python-all.ru/3.2/library/test.html#module-test) предназначен только для внутреннего использования Python. Он документирован для пользы основных разработчиков Python. Любое использование этого пакета за пределами стандартной библиотеки Python не рекомендуется, так как упомянутый здесь код может быть изменён или удалён без предупреждения между выпусками Python.1213Пакет [`test`](https://python-all.ru/3.2/library/test.html#module-test) содержит все регрессионные тесты для Python, а также модули [`test.support`](https://python-all.ru/3.2/library/test.html#module-test.support) и `test.regrtest`. [`test.support`](https://python-all.ru/3.2/library/test.html#module-test.support) используется для улучшения тестов, а `test.regrtest` управляет набором тестов.1415Каждый модуль в пакете [`test`](https://python-all.ru/3.2/library/test.html#module-test), имя которого начинается с `test_`, является набором тестов для конкретного модуля или функции. Все новые тесты следует писать с использованием модуля [`unittest`](https://python-all.ru/3.2/library/unittest.html#module-unittest) или [`doctest`](https://python-all.ru/3.2/library/doctest.html#module-doctest). Некоторые старые тесты написаны в «традиционном» стиле тестирования, который сравнивает вывод, напечатанный в `sys.stdout`; такой стиль тестов считается устаревшим.1617> **См. также**18>19> **Модуль [`unittest`](https://python-all.ru/3.2/library/unittest.html#module-unittest)**20>21> Написание регрессионных тестов PyUnit.22>23> **Модуль [`doctest`](https://python-all.ru/3.2/library/doctest.html#module-doctest)**24>25> Тесты, встроенные в строки документации.2627## 25.5.1. Написание модульных тестов для пакета [`test`](https://python-all.ru/3.2/library/test.html#module-test)2829Рекомендуется, чтобы тесты, использующие модуль [`unittest`](https://python-all.ru/3.2/library/unittest.html#module-unittest), следовали нескольким рекомендациям. Одна из них – называть тестовый модуль, начиная его с `test_` и заканчивая именем тестируемого модуля. Методы тестирования в тестовом модуле должны начинаться с `test_` и заканчиваться описанием того, что тестирует метод. Это необходимо, чтобы драйвер тестов распознавал методы как тестовые. Кроме того, не следует включать строку документации для метода. Вместо этого следует использовать комментарий (например, `# Тестирует функция возвращает только True или False`) для документирования тестовых методов. Это сделано потому, что строки документации выводятся на печать, если они существуют, и, таким образом, не указывается, какой именно тест выполняется.3031Часто используется стандартная заготовка:3233```python34import unittest35from test import support3637class MyTestCase1(unittest.TestCase):3839    # Используйте setUp() и tearDown() только при необходимости4041    def setUp(self):42        ... code to execute in preparation for tests ...4344    def tearDown(self):45        ... code to execute to clean up after tests ...4647    def test_feature_one(self):48        # Тест первой возможности.49        ... testing code ...5051    def test_feature_two(self):52        # Тест второй возможности.53        ... testing code ...5455    ... more test methods ...5657class MyTestCase2(unittest.TestCase):58    ... same structure as MyTestCase1 ...5960... more test classes ...6162def test_main():63    support.run_unittest(MyTestCase1,64                              MyTestCase2,65                              ... list other tests ...66                             )6768if __name__ == '__main__':69    test_main()70```7172Этот шаблонный код позволяет запускать тестовый набор как с помощью `test.regrtest`, так и самостоятельно в качестве скрипта.7374Цель регрессионного тестирования – попытаться сломать код. Это приводит к нескольким правилам, которым следует следовать:7576- Набор тестов должен задействовать все классы, функции и константы. Это включает не только внешний API, который будет представлен внешнему миру, но и «приватный» код.77- Предпочтительно тестирование методом белого ящика (анализ тестируемого кода при написании тестов). Тестирование методом чёрного ящика (тестирование только опубликованного пользовательского интерфейса) недостаточно для проверки всех граничных и крайних случаев.78- Убедитесь, что все возможные значения протестированы, включая недопустимые. Это гарантирует, что не только все допустимые значения принимаются, но и неправильные значения обрабатываются корректно.79- Исчерпайте как можно больше путей выполнения кода. Тестируйте места ветвления и соответственно подбирайте входные данные, чтобы гарантировать, что проходит как можно больше различных путей.80- Добавляйте явные тесты для любых ошибок, обнаруженных в тестируемом коде. Это гарантирует, что ошибка не возникнет снова, если код будет изменён в будущем.81- Убедитесь, что после тестов выполнена очистка (например, закрыты и удалены все временные файлы).82- Если тест зависит от конкретного условия операционной системы, то проверьте, что условие уже выполняется, прежде чем запускать тест.83- Импортируйте как можно меньше модулей и делайте это как можно раньше. Это минимизирует внешние зависимости тестов, а также уменьшает возможные аномальные поведения из-за побочных эффектов импорта модуля.84- Старайтесь максимально повторно использовать код. Иногда тесты могут различаться такой мелочью, как тип используемых входных данных. Минимизируйте дублирование кода, создавая подкласс базового тестового класса, который определяет входные данные:8586  ```python87  class TestFuncAcceptsSequences(unittest.TestCase):8889      func = mySuperWhammyFunction9091      def test_func(self):92          self.func(self.arg)9394  class AcceptLists(TestFuncAcceptsSequences):95      arg = [1, 2, 3]9697  class AcceptStrings(TestFuncAcceptsSequences):98      arg = 'abc'99100  class AcceptTuples(TestFuncAcceptsSequences):101      arg = (1, 2, 3)102  ```103104> **См. также**105>106> **Разработка через тестирование**107>108> Книга Кента Бека о написании тестов до кода.109110## 25.5.2. Запуск тестов с помощью интерфейса командной строки111112Пакет [`test`](https://python-all.ru/3.2/library/test.html#module-test) можно запускать как скрипт для управления регрессионным набором тестов Python благодаря опции [*-m*](https://python-all.ru/3.2/using/cmdline.html#cmdoption-m): **python -m test**. Под капотом он использует `test.regrtest`; вызов **python -m test.regrtest**, использовавшийся в предыдущих версиях Python, всё ещё работает). Запуск скрипта самостоятельно автоматически запускает выполнение всех регрессионных тестов в пакете [`test`](https://python-all.ru/3.2/library/test.html#module-test). Это делается путём поиска всех модулей в пакете, имена которых начинаются с `test_`, их импорта и выполнения функции `test_main()`, если она присутствует. Имена тестов для выполнения также можно передать скрипту. Указание одного регрессионного теста (**python -m test test\_spam**) минимизирует вывод и печатает только результат теста (пройден или не пройден), тем самым минимизируя вывод.113114Запуск [`test`](https://python-all.ru/3.2/library/test.html#module-test) напрямую позволяет задать, какие ресурсы доступны для использования тестам. Это делается с помощью опции командной строки `-u`. Указание `all` в качестве значения опции `-u` включает все возможные ресурсы: **python -m test -uall**. Если нужны все ресурсы, кроме одного (более частый случай), после `all` можно перечислить через запятую ресурсы, которые не нужны. Команда **python -m test -uall,-audio,-largefile** запустит [`test`](https://python-all.ru/3.2/library/test.html#module-test) со всеми ресурсами, кроме `audio` и `largefile`. Для списка всех ресурсов и дополнительных опций командной строки выполните **python -m test -h**.115116Некоторые другие способы выполнения регрессионных тестов зависят от платформы, на которой они выполняются. В Unix можно выполнить **make test** в корневом каталоге, где был собран Python. В Windows выполнение **rt.bat** из каталога `PCBuild` запустит все регрессионные тесты.117118# 25.6. [`test.support`](https://python-all.ru/3.2/library/test.html#module-test.support) – Утилиты для набора тестов Python119120Модуль [`test.support`](https://python-all.ru/3.2/library/test.html#module-test.support) обеспечивает поддержку набора регрессионных тестов Python.121122> **Примечание**123>124> [`test.support`](https://python-all.ru/3.2/library/test.html#module-test.support) не является публичным модулем. Он документирован здесь, чтобы помочь разработчикам Python писать тесты. API этого модуля может изменяться без обеспечения обратной совместимости между выпусками.125126В этом модуле определены следующие исключения:127128#### `exception test.support.TestFailed`129130Исключение, возбуждаемое при сбое теста. Это устарело в пользу тестов на основе [`unittest`](https://python-all.ru/3.2/library/unittest.html#module-unittest) и методов утверждений [`unittest.TestCase`](https://python-all.ru/3.2/library/unittest.html#unittest.TestCase).131132#### `exception test.support.ResourceDenied`133134Подкласс [`unittest.SkipTest`](https://python-all.ru/3.2/library/unittest.html#unittest.SkipTest). Возбуждается, когда ресурс (например, сетевое соединение) недоступен. Возбуждается функцией [`requires()`](https://python-all.ru/3.2/library/test.html#test.support.requires).135136Модуль [`test.support`](https://python-all.ru/3.2/library/test.html#module-test.support) определяет следующие константы:137138#### `test.support.verbose`139140[`True`](https://python-all.ru/3.2/library/constants.html#True), если включён подробный вывод. Следует проверять, когда требуется более детальная информация о выполняющемся тесте. *verbose* устанавливается `test.regrtest`.141142#### `test.support.is_jython`143144[`True`](https://python-all.ru/3.2/library/constants.html#True), если текущий интерпретатор – Jython.145146#### `test.support.TESTFN`147148Устанавливается в имя, безопасное для использования в качестве имени временного файла. Любой созданный временный файл должен быть закрыт и удалён.149150Модуль [`test.support`](https://python-all.ru/3.2/library/test.html#module-test.support) определяет следующие функции:151152#### `test.support.forget(module_name)`153154Удаляет модуль с именем *module\_name* из `sys.modules` и удаляет все скомпилированные в байт-код файлы этого модуля.155156#### `test.support.is_resource_enabled(resource)`157158Возвращает [`True`](https://python-all.ru/3.2/library/constants.html#True), если *resource* включён и доступен. Список доступных ресурсов устанавливается только при выполнении тестов `test.regrtest`.159160#### `test.support.requires(resource, msg=None)`161162Вызывает [`ResourceDenied`](https://python-all.ru/3.2/library/test.html#test.support.ResourceDenied), если *resource* недоступен. *msg* – это аргумент для [`ResourceDenied`](https://python-all.ru/3.2/library/test.html#test.support.ResourceDenied), если он возбуждён. Всегда возвращает [`True`](https://python-all.ru/3.2/library/constants.html#True), если вызывается из функции, чьё `__name__` равно `'__main__'`. Используется при выполнении тестов `test.regrtest`.163164#### `test.support.findfile(filename)`165166Возвращает путь к файлу с именем *filename*. Если совпадений не найдено, возвращается *filename*. Это не считается ошибкой, так как оно может быть путём к файлу.167168#### `test.support.run_unittest(*classes)`169170Выполняет подклассы [`unittest.TestCase`](https://python-all.ru/3.2/library/unittest.html#unittest.TestCase), переданные в функцию. Функция просматривает классы в поисках методов, начинающихся с префикса `test_`, и выполняет тесты по отдельности.171172Также допускается передача строк в качестве параметров; они должны быть ключами в `sys.modules`. Каждый соответствующий модуль будет просканирован с помощью `unittest.TestLoader.loadTestsFromModule()`. Обычно это встречается в следующей функции `test_main()`:173174```python175def test_main():176    support.run_unittest(__name__)177```178179Это запустит все тесты, определенные в указанном модуле.180181#### `test.support.check_warnings(*filters, quiet=True)`182183Удобная обёртка для [`warnings.catch_warnings()`](https://python-all.ru/3.2/library/warnings.html#warnings.catch_warnings), упрощающая проверку того, что предупреждение было правильно вызвано. Она примерно эквивалентна вызову `warnings.catch_warnings(record=True)` с [`warnings.simplefilter()`](https://python-all.ru/3.2/library/warnings.html#warnings.simplefilter), установленным в `always`, и возможностью автоматически проверять записанные результаты.184185`check_warnings` принимает 2-кортежи вида `("message regexp", WarningCategory)` в качестве позиционных аргументов. Если указан один или несколько *filters*, или необязательный ключевой аргумент *quiet* равен [`False`](https://python-all.ru/3.2/library/constants.html#False), то проверяется, что предупреждения соответствуют ожидаемым: каждый указанный фильтр должен совпадать хотя бы с одним предупреждением, возбуждённым вложенным кодом, иначе тест не пройден; если возбуждены какие-либо предупреждения, не совпадающие ни с одним из указанных фильтров, тест также не пройден. Чтобы отключить первую из этих проверок, установите *quiet* в [`True`](https://python-all.ru/3.2/library/constants.html#True).186187Если аргументы не указаны, по умолчанию используется:188189```python190check_warnings(("", Warning), quiet=True)191```192193В этом случае перехватываются все предупреждения и исключения не возбуждаются.194195При входе в контекстный менеджер возвращается экземпляр `WarningRecorder`. Базовый список предупреждений из [`catch_warnings()`](https://python-all.ru/3.2/library/warnings.html#warnings.catch_warnings) доступен через атрибут [`warnings`](https://python-all.ru/3.2/library/warnings.html#module-warnings) объекта-регистратора. Для удобства атрибуты объекта, представляющего самое последнее предупреждение, также можно получить напрямую через объект-регистратор (см. пример ниже). Если предупреждений не было, то любой из атрибутов, которые обычно ожидаются у объекта, представляющего предупреждение, вернёт [`None`](https://python-all.ru/3.2/library/constants.html#None).196197Объект recorder также имеет метод `reset()`, который очищает список предупреждений.198199Менеджер контекста предназначен для использования следующим образом:200201```python202with check_warnings(("assertion is always true", SyntaxWarning),203                    ("", UserWarning)):204    exec('assert(False, "Hey!")')205    warnings.warn(UserWarning("Hide me!"))206```207208В этом случае, если одно из предупреждений не было вызвано или было вызвано другое предупреждение, [`check_warnings()`](https://python-all.ru/3.2/library/test.html#test.support.check_warnings) вызовет ошибку.209210Когда тесту требуется более глубоко изучить предупреждения, а не просто проверить, были ли они, можно использовать такой код:211212```python213with check_warnings(quiet=True) as w:214    warnings.warn("foo")215    assert str(w.args[0]) == "foo"216    warnings.warn("bar")217    assert str(w.args[0]) == "bar"218    assert str(w.warnings[0].args[0]) == "foo"219    assert str(w.warnings[1].args[0]) == "bar"220    w.reset()221    assert len(w.warnings) == 0222```223224Здесь будут перехвачены все предупреждения, и тестовый код напрямую проверяет перехваченные предупреждения.225226Изменено в версии 3.2: Новые необязательные аргументы *filters* и *quiet*.227228#### `test.support.captured_stdout()`229230Это контекстный менеджер, который выполняет тело инструкции [`with`](https://python-all.ru/3.2/reference/compound_stmts.html#with), используя объект `StringIO.StringIO` в качестве sys.stdout. Этот объект можно получить с помощью предложения `as` инструкции [`with`](https://python-all.ru/3.2/reference/compound_stmts.html#with).231232Пример использования:233234```python235with captured_stdout() as s:236    print("hello")237assert s.getvalue() == "hello\n"238```239240#### `test.support.suppress_crash_popup()`241242Контекстный менеджер, отключающий диалоги отчётов об ошибках Windows с помощью [SetErrorMode](https://python-all.ru/3.2/library/test.html). На других платформах он не выполняет никаких действий.243244#### `test.support.import_module(name, deprecated=False)`245246Эта функция импортирует и возвращает указанный модуль. В отличие от обычного импорта, если модуль не удается импортировать, функция генерирует исключение [`unittest.SkipTest`](https://python-all.ru/3.2/library/unittest.html#unittest.SkipTest).247248Сообщения об устаревании модулей и пакетов подавляются во время этого импорта, если *устарело* равно [`True`](https://python-all.ru/3.2/library/constants.html#True).249250Новое в версии 3.1.251252#### `test.support.import_fresh_module(name, fresh=(), blocked=(), deprecated=False)`253254Эта функция импортирует и возвращает свежую копию указанного модуля Python, удаляя его из `sys.modules` перед выполнением импорта. Обратите внимание, что, в отличие от `reload()`, оригинальный модуль не затрагивается этой операцией.255256Параметр *fresh* – это итерируемая последовательность дополнительных имен модулей, которые также удаляются из кеша `sys.modules` перед выполнением импорта.257258*blocked* – это итерируемый объект с именами модулей, которые заменяются на `0` в кеше модулей во время импорта, чтобы гарантировать, что попытки их импорта вызовут [`ImportError`](https://python-all.ru/3.2/library/exceptions.html#ImportError).259260Указанный модуль и все модули, перечисленные в параметрах *fresh* и *blocked*, сохраняются до начала импорта, а затем повторно вставляются в `sys.modules` после завершения свежего импорта.261262Сообщения об устаревании модулей и пакетов подавляются во время этого импорта, если *устарело* равно [`True`](https://python-all.ru/3.2/library/constants.html#True).263264Эта функция вызовет [`unittest.SkipTest`](https://python-all.ru/3.2/library/unittest.html#unittest.SkipTest), если указанный модуль не удаётся импортировать.265266Пример использования:267268```python269# Получить копии модуля warnings для тестирования без270# влияния на версию, используемую остальной частью тестового набора271# Одна копия использует реализацию на C, другая вынуждена использовать272# резервную реализацию на чистом Python273py_warnings = import_fresh_module('warnings', blocked=['_warnings'])274c_warnings = import_fresh_module('warnings', fresh=['_warnings'])275```276277Новое в версии 3.1.278279Модуль [`test.support`](https://python-all.ru/3.2/library/test.html#module-test.support) определяет следующие классы:280281#### `class test.support.TransientResource(exc, **kwargs)`282283Экземпляры представляют собой менеджер контекста, который генерирует исключение [`ResourceDenied`](https://python-all.ru/3.2/library/test.html#test.support.ResourceDenied), если возникает указанный тип исключения. Все именованные аргументы обрабатываются как пары атрибут/значение для сравнения с любым исключением, возникшим внутри блока [`with`](https://python-all.ru/3.2/reference/compound_stmts.html#with). Исключение [`ResourceDenied`](https://python-all.ru/3.2/library/test.html#test.support.ResourceDenied) возбуждается только в том случае, если все пары правильно совпадают с атрибутами исключения.284285#### `class test.support.EnvironmentVarGuard`286287Класс, используемый для временной установки или сброса переменных окружения. Экземпляры можно использовать как менеджер контекста; они имеют полноценный интерфейс словаря для запроса/изменения базового `os.environ`. После выхода из менеджера контекста все изменения переменных окружения, сделанные через этот экземпляр, будут отменены.288289Изменено в версии 3.1: Добавлен интерфейс словаря.290291#### `EnvironmentVarGuard.set(envvar, value)`292293Временно устанавливает переменную окружения `envvar` в значение `value`.294295#### `EnvironmentVarGuard.unset(envvar)`296297Временно сбрасывает переменную окружения `envvar`.298299#### `class test.support.WarningsRecorder`300301Класс, используемый для записи предупреждений в модульных тестах. Дополнительные сведения см. в описании [`check_warnings()`](https://python-all.ru/3.2/library/test.html#test.support.check_warnings) выше.302