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

test.md

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

1> **Источник:** https://python-all.ru/3.1/library/test.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# 25.5. `test` – Пакет регрессионных тестов для Python89> **Предупреждение**10>11> Пакет `test` предназначен только для внутреннего использования Python. Он dокументирован для разработчиков ядра Python. Любое использование этого пакета за пределами стандартной библиотеки Python не рекомендуется, так как упомянутый здесь код может быть изменён или удалён без предупреждения между выпусками Python.1213Пакет `test` содержит все регрессионные тесты для Python, а также модули `test.support` и `test.regrtest`. `test.support` используется для улучшения тестов, а `test.regrtest` управляет набором тестов.1415Каждый модуль в пакете `test`, имя которого начинается с `test_`, является набором тестов для определённого модуля или функции. Все новые тесты должны быть написаны с использованием модуля [`unittest`](https://python-all.ru/3.1/library/unittest.html#module-unittest) или [`doctest`](https://python-all.ru/3.1/library/doctest.html#module-doctest). Некоторые старые тесты написаны в «традиционном» стиле, который сравнивает вывод, отправленный в `sys.stdout`; такой стиль считается устаревшим.1617> **См. также**18>19> **Модуль [`unittest`](https://python-all.ru/3.1/library/unittest.html#module-unittest)**20>21> Написание регрессионных тестов PyUnit.22>23> **Модуль [`doctest`](https://python-all.ru/3.1/library/doctest.html#module-doctest)**24>25> Тесты, встроенные в строки документации.2627## 25.5.1. Написание модульных тестов для пакета `test`2829Рекомендуется, чтобы тесты, использующие модуль [`unittest`](https://python-all.ru/3.1/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.regrtest` может быть запущен как скрипт для управления набором регрессионных тестов Python благодаря опции *-m*: **python -m test.regrtest**. Запуск скрипта без аргументов автоматически запускает все регрессионные тесты в пакете `test`. Это достигается нахождением всех модулей в пакете, имена которых начинаются с `test_`, их импортированием и выполнением функции `test_main()`, если она присутствует. Имена тестов для выполнения также могут быть переданы скрипту. Указание одного регрессионного теста (**python -m test.regrtest test\_spam**) минимизирует вывод и будет выводить только то, прошёл тест или нет, тем самым уменьшая объём вывода.113114Прямой запуск `test.regrtest` позволяет задать, какие ресурсы доступны для использования тестами. Для этого используется опция командной строки *-u*. Выполните **python -m test.regrtest -uall**, чтобы включить все ресурсы; указание `all` в качестве значения опции `-u` включает все возможные ресурсы. Если нужны все ресурсы, кроме одного (более распространённый случай), после `all` можно указать разделённый запятыми список ресурсов, которые не нужны. Команда **python -m test.regrtest -uall,-audio,-largefile** запустит `test.regrtest` со всеми ресурсами, кроме `audio` и `largefile`. Чтобы увидеть список всех ресурсов и дополнительные опции командной строки, выполните **python -m test.regrtest -h**.115116Некоторые другие способы выполнения регрессионных тестов зависят от платформы, на которой они выполняются. В Unix можно выполнить **make test** в корневом каталоге, где была собрана Python. В Windows выполнение **rt.bat** из каталога `PCBuild` запустит все регрессионные тесты.117118# 25.6. `test.support` – Вспомогательные функции для тестов119120Модуль `test.support` предоставляет поддержку для регрессионных тестов Python.121122В этом модуле определены следующие исключения:123124#### `exception test.support.TestFailed`125126Исключение, возбуждаемое при сбое теста. Это устарело в пользу тестов на основе127128[`unittest`](https://python-all.ru/3.1/library/unittest.html#module-unittest)129130и методов утверждений131132[`unittest.TestCase`](https://python-all.ru/3.1/library/unittest.html#unittest.TestCase)133134.135136#### `exception test.support.TestSkipped`137138Подкласс139140[`TestFailed`](https://python-all.ru/3.1/library/test.html#test.support.TestFailed)141142. Возникает, когда тест пропускается. Это происходит, когда необходимый ресурс (например, сетевое соединение) недоступен на момент тестирования.143144#### `exception test.support.ResourceDenied`145146Подкласс147148[`TestSkipped`](https://python-all.ru/3.1/library/test.html#test.support.TestSkipped)149150. Возникает, когда ресурс (например, сетевое соединение) недоступен. Вызывается функцией151152[`requires()`](https://python-all.ru/3.1/library/test.html#test.support.requires)153154.155156Модуль `test.support` определяет следующие константы:157158#### `test.support.verbose`159160[`True`](https://python-all.ru/3.1/library/constants.html#True)161162, если включён подробный вывод. Следует проверять, когда требуется более детальная информация о выполняющемся тесте.163164*verbose*165166устанавливается167168`test.regrtest`169170.171172#### `test.support.is_jython`173174[`True`](https://python-all.ru/3.1/library/constants.html#True)175176, если текущий интерпретатор – Jython.177178#### `test.support.TESTFN`179180Устанавливается в путь, по которому может быть создан временный файл. Любой созданный временный файл должен быть закрыт и удалён.181182Модуль `test.support` определяет следующие функции:183184#### `test.support.forget(module_name)`185186Удаляет модуль с именем187188*module\_name*189190из191192`sys.modules`193194и удаляет любые откомпилированные файлы этого модуля.195196#### `test.support.is_resource_enabled(resource)`197198Возвращает199200[`True`](https://python-all.ru/3.1/library/constants.html#True)201202, если203204*resource*205206включён и доступен. Список доступных ресурсов устанавливается только тогда, когда207208`test.regrtest`209210выполняет тесты.211212#### `test.support.requires(resource, msg=None)`213214Вызывает215216[`ResourceDenied`](https://python-all.ru/3.1/library/test.html#test.support.ResourceDenied)217218, если219220*resource*221222недоступен.223224*msg*225226является аргументом для227228[`ResourceDenied`](https://python-all.ru/3.1/library/test.html#test.support.ResourceDenied)229230, если он вызывается. Всегда возвращает true, если вызывается функцией,231232`__name__`233234которой равно235236`'__main__'`237238. Используется, когда тесты выполняются с помощью239240`test.regrtest`241242.243244#### `test.support.findfile(filename)`245246Возвращает путь к файлу с именем247248*filename*249250. Если совпадение не найдено, возвращается251252*filename*253254. Это не считается ошибкой, поскольку это может быть путь к файлу.255256#### `test.support.run_unittest(*classes)`257258Выполняет подклассы [`unittest.TestCase`](https://python-all.ru/3.1/library/unittest.html#unittest.TestCase), переданные в функцию. Функция сканирует классы на наличие методов, начинающихся с префикса `test_`, и выполняет тесты по отдельности.259260Также допускается передача строк в качестве параметров; они должны быть ключами в `sys.modules`. Каждый соответствующий модуль будет просканирован с помощью `unittest.TestLoader.loadTestsFromModule()`. Обычно это встречается в следующей функции `test_main()`:261262```python263def test_main():264    support.run_unittest(__name__)265```266267Это запустит все тесты, определенные в указанном модуле.268269#### `test.support.check_warnings()`270271Удобная обёртка для `warnings.catch_warnings()`, которая упрощает проверку того, что предупреждение было правильно вызвано с помощью одной проверки. Она примерно эквивалентна вызову `warnings.catch_warnings(record=True)`.272273Основное отличие в том, что при входе в менеджер контекста возвращается экземпляр `WarningRecorder`, а не простой список. Базовый список предупреждений доступен через атрибут `warnings` объекта-регистратора, а атрибуты последнего вызванного предупреждения также доступны напрямую через этот объект. Если ни одного предупреждения не было вызвано, то все эти атрибуты будут равны [`None`](https://python-all.ru/3.1/library/constants.html#None).274275На объекте-регистраторе также предоставляется метод `reset()`. Этот метод просто очищает список предупреждений.276277Менеджер контекста используется следующим образом:278279```python280with check_warnings() as w:281    warnings.simplefilter("always")282    warnings.warn("foo")283    assert str(w.message) == "foo"284    warnings.warn("bar")285    assert str(w.message) == "bar"286    assert str(w.warnings[0].message) == "foo"287    assert str(w.warnings[1].message) == "bar"288    w.reset()289    assert len(w.warnings) == 0290```291292#### `test.support.captured_stdout()`293294Это контекстный менеджер, который выполняет тело инструкции [`with`](https://python-all.ru/3.1/reference/compound_stmts.html#with), используя объект `StringIO.StringIO` в качестве sys.stdout. Этот объект можно получить с помощью предложения `as` инструкции [`with`](https://python-all.ru/3.1/reference/compound_stmts.html#with).295296Пример использования:297298```python299with captured_stdout() as s:300    print("hello")301assert s.getvalue() == "hello"302```303304#### `test.support.import_module(name, deprecated=False)`305306Эта функция импортирует и возвращает указанный модуль. В отличие от обычного импорта, эта функция вызывает `unittest.SkipTest`, если модуль не может быть импортирован.307308Сообщения об устаревании модулей и пакетов подавляются во время этого импорта, если *устарело* равно [`True`](https://python-all.ru/3.1/library/constants.html#True).309310Новое в версии 3.1.311312#### `test.support.import_fresh_module(name, fresh=(), blocked=(), deprecated=False)`313314Эта функция импортирует и возвращает свежую копию указанного модуля Python, удаляя его из `sys.modules` перед выполнением импорта. Обратите внимание, что, в отличие от `reload()`, оригинальный модуль не затрагивается этой операцией.315316Параметр *fresh* – это итерируемая последовательность дополнительных имен модулей, которые также удаляются из кеша `sys.modules` перед выполнением импорта.317318*blocked* – это итерируемый объект с именами модулей, которые заменяются на `0` в кеше модулей во время импорта, чтобы гарантировать, что попытки их импорта вызовут [`ImportError`](https://python-all.ru/3.1/library/exceptions.html#ImportError).319320Указанный модуль и все модули, перечисленные в параметрах *fresh* и *blocked*, сохраняются до начала импорта, а затем повторно вставляются в `sys.modules` после завершения свежего импорта.321322Сообщения об устаревании модулей и пакетов подавляются во время этого импорта, если *устарело* равно [`True`](https://python-all.ru/3.1/library/constants.html#True).323324Эта функция вызывает `unittest.SkipTest`, если указанный модуль не может быть импортирован.325326Пример использования:327328```python329# Получить копии модуля warnings для тестирования без330# влияния на версию, используемую остальной частью тестового набора331# Одна копия использует реализацию на C, другая вынуждена использовать332# резервную реализацию на чистом Python333py_warnings = import_fresh_module('warnings', blocked=['_warnings'])334c_warnings = import_fresh_module('warnings', fresh=['_warnings'])335```336337Новое в версии 3.1.338339Модуль `test.support` определяет следующие классы:340341#### `class test.support.TransientResource(exc, **kwargs)`342343Экземпляры представляют собой менеджер контекста, который генерирует исключение344345[`ResourceDenied`](https://python-all.ru/3.1/library/test.html#test.support.ResourceDenied)346347, если возникает указанный тип исключения. Все именованные аргументы обрабатываются как пары атрибут/значение для сравнения с любым исключением, возникшим внутри блока348349[`with`](https://python-all.ru/3.1/reference/compound_stmts.html#with)350351. Исключение352353[`ResourceDenied`](https://python-all.ru/3.1/library/test.html#test.support.ResourceDenied)354355возбуждается только в том случае, если все пары правильно совпадают с атрибутами исключения.356357#### `class test.support.EnvironmentVarGuard`358359Класс, используемый для временной установки или сброса переменных окружения. Экземпляры можно использовать как менеджер контекста, и они имеют полный интерфейс словаря для запроса/изменения базового `os.environ`. После выхода из менеджера контекста все изменения переменных окружения, сделанные через этот экземпляр, будут отменены.360361Изменено в версии 3.1: Добавлен интерфейс словаря.362363#### `EnvironmentVarGuard.set(envvar, value)`364365Временно устанавливает переменную окружения366367`envvar`368369в значение370371`value`372373.374375#### `EnvironmentVarGuard.unset(envvar)`376377Временно сбрасывает переменную окружения378379`envvar`380381.382383#### `class test.support.WarningsRecorder`384385Класс, используемый для записи предупреждений в модульных тестах. Дополнительные сведения см. в описании386387[`check_warnings()`](https://python-all.ru/3.1/library/test.html#test.support.check_warnings)388389выше.390