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

test.md

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

1> **Источник:** https://python-all.ru/2.7/library/test.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# 25.5. [`test`](https://python-all.ru/2.7/library/test.html#module-test) – Пакет регрессионных тестов для Python89> **Примечание**10>11> Пакет [`test`](https://python-all.ru/2.7/library/test.html#module-test) предназначен только для внутреннего использования Python. Он dокументирован для разработчиков ядра Python. Использование этого пакета за пределами стандартной библиотеки Python не рекомендуется, так как упомянутый здесь код может быть изменён или удалён без уведомления между выпусками Python.1213Пакет [`test`](https://python-all.ru/2.7/library/test.html#module-test) содержит все регрессионные тесты для Python, а также модули [`test.support`](https://python-all.ru/2.7/library/test.html#module-test.support) и `test.regrtest`. [`test.support`](https://python-all.ru/2.7/library/test.html#module-test.support) используется для расширения возможностей тестов, а `test.regrtest` управляет набором тестов.1415Каждый модуль в пакете [`test`](https://python-all.ru/2.7/library/test.html#module-test), имя которого начинается с `test_`, является набором тестов для конкретного модуля или функции. Все новые тесты следует писать с использованием модулей [`unittest`](https://python-all.ru/2.7/library/unittest.html#module-unittest) или [`doctest`](https://python-all.ru/2.7/library/doctest.html#module-doctest). Некоторые старые тесты написаны в «традиционном» стиле тестирования, сравнивающем вывод, направленный в `sys.stdout`; такой стиль теста считается устаревшим.1617> **См. также**18>19> **Модуль [`unittest`](https://python-all.ru/2.7/library/unittest.html#module-unittest)**20>21> Написание регрессионных тестов PyUnit.22>23> **Модуль [`doctest`](https://python-all.ru/2.7/library/doctest.html#module-doctest)**24>25> Тесты, встроенные в строки документации.2627## 25.5.1. Написание модульных тестов для пакета [`test`](https://python-all.ru/2.7/library/test.html#module-test)2829Для тестов, использующих модуль [`unittest`](https://python-all.ru/2.7/library/unittest.html#module-unittest), рекомендуется следовать нескольким правилам. Одно из них – называть модуль тестов, начиная его имя с `test_` и заканчивая названием тестируемого модуля. Методы тестов в модуле тестирования должны начинаться с `test_` и заканчиваться описанием того, что метод тестирует. Это необходимо, чтобы тестовый драйвер распознавал методы как тестовые. Кроме того, не следует включать строку документации для метода. Вместо этого следует использовать комментарий (например, `# Tests function returns only True or 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`](https://python-all.ru/2.7/using/cmdline.html#cmdoption-m): **python -m test.regrtest**. Запуск скрипта самостоятельно автоматически начинает выполнение всех регрессионных тестов в пакете [`test`](https://python-all.ru/2.7/library/test.html#module-test). Это делается путём поиска всех модулей в пакете, чьи имена начинаются с `test_`, их импорта и выполнения функции `test_main()`, если она присутствует. Имена тестов для выполнения также можно передать скрипту. Указание одного регрессионного теста (**python -m test.regrtest test\_spam**) минимизирует вывод и печатает только то, прошёл тест или нет, тем самым уменьшая объём вывода.113114Запуск `test.regrtest` напрямую позволяет задать, какие ресурсы доступны для использования тестами. Для этого используется опция командной строки `-u`. Указание `all` в качестве значения для опции `-u` включает все возможные ресурсы: **python -m test.regrtest -uall**. Если требуется все, кроме одного ресурса (более частый случай), после `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Изменено в версии 2.7.14: Пакет [`test`](https://python-all.ru/2.7/library/test.html#module-test) можно запускать как скрипт: **python -m test**. Это работает так же, как запуск модуля `test.regrtest`.119120# 25.6. [`test.support`](https://python-all.ru/2.7/library/test.html#module-test.support) – Вспомогательные функции для тестов121122> **Примечание**123>124> Модуль `test.test_support` был переименован в [`test.support`](https://python-all.ru/2.7/library/test.html#module-test.support) в Python 3.x и 2.7.14. Имя `test.test_support` сохранено как псевдоним в 2.7.125126Модуль [`test.support`](https://python-all.ru/2.7/library/test.html#module-test.support) обеспечивает поддержку регрессионных тестов Python.127128В этом модуле определены следующие исключения:129130#### `exception test.support.TestFailed`131132Исключение, которое вызывается при неудаче теста. Устарело в пользу тестов на основе [`unittest`](https://python-all.ru/2.7/library/unittest.html#module-unittest) и методов утверждений [`unittest.TestCase`](https://python-all.ru/2.7/library/unittest.html#unittest.TestCase).133134#### `exception test.support.ResourceDenied`135136Подкласс [`unittest.SkipTest`](https://python-all.ru/2.7/library/unittest.html#unittest.SkipTest). Возбуждается, когда ресурс (например, сетевое соединение) недоступен. Возбуждается функцией [`requires()`](https://python-all.ru/2.7/library/test.html#test.support.requires).137138Модуль [`test.support`](https://python-all.ru/2.7/library/test.html#module-test.support) определяет следующие константы:139140#### `test.support.verbose`141142[`True`](https://python-all.ru/2.7/library/constants.html#True), если включен подробный вывод. Следует проверять, когда требуется более детальная информация о выполняющемся тесте. *verbose* устанавливается `test.regrtest`.143144#### `test.support.have_unicode`145146[`True`](https://python-all.ru/2.7/library/constants.html#True) если доступна поддержка Unicode.147148#### `test.support.is_jython`149150[`True`](https://python-all.ru/2.7/library/constants.html#True), если запущенный интерпретатор – Jython.151152#### `test.support.TESTFN`153154Устанавливается в имя, безопасное для использования в качестве имени временного файла. Любой созданный временный файл должен быть закрыт и удалён.155156#### `test.support.TEST_HTTP_URL`157158Определяет URL выделенного HTTP-сервера для сетевых тестов.159160Модуль [`test.support`](https://python-all.ru/2.7/library/test.html#module-test.support) определяет следующие функции:161162#### `test.support.forget(module_name)`163164Удаляет модуль *module\_name* из `sys.modules` и удаляет все скомпилированные в байт-код файлы этого модуля.165166#### `test.support.is_resource_enabled(resource)`167168Возвращает [`True`](https://python-all.ru/2.7/library/constants.html#True), если *resource* включён и доступен. Список доступных ресурсов задаётся только при выполнении тестов `test.regrtest`.169170#### `test.support.requires(resource[, msg])`171172Возбуждает [`ResourceDenied`](https://python-all.ru/2.7/library/test.html#test.support.ResourceDenied), если *resource* недоступен. *msg* – это аргумент для [`ResourceDenied`](https://python-all.ru/2.7/library/test.html#test.support.ResourceDenied), если он возбуждается. Всегда возвращает [`True`](https://python-all.ru/2.7/library/constants.html#True), если вызвана из функции, чей `__name__` равен `'__main__'`. Используется при выполнении тестов с помощью `test.regrtest`.173174#### `test.support.findfile(filename)`175176Возвращает путь к файлу с именем *filename*. Если совпадений не найдено, возвращается *filename*. Это не считается ошибкой, так как оно может быть путём к файлу.177178#### `test.support.run_unittest(*classes)`179180Выполняет подклассы [`unittest.TestCase`](https://python-all.ru/2.7/library/unittest.html#unittest.TestCase), переданные функции. Функция сканирует классы на наличие методов, начинающихся с префикса `test_`, и выполняет тесты по отдельности.181182Также допускается передавать строки в качестве параметров; они должны быть ключами в `sys.modules`. Каждый связанный модуль будет просканирован функцией `unittest.TestLoader.loadTestsFromModule()`. Обычно это встречается в следующей функции `test_main()`:183184```python185def test_main():186    support.run_unittest(__name__)187```188189Это запустит все тесты, определенные в указанном модуле.190191#### `test.support.check_warnings(*filters, quiet=True)`192193Удобная обёртка для [`warnings.catch_warnings()`](https://python-all.ru/2.7/library/warnings.html#warnings.catch_warnings), упрощающая проверку того, что предупреждение было корректно возбуждено. Она примерно эквивалентна вызову `warnings.catch_warnings(record=True)` с [`warnings.simplefilter()`](https://python-all.ru/2.7/library/warnings.html#warnings.simplefilter), установленным в `always`, и с возможностью автоматической проверки записанных результатов.194195`check_warnings` принимает кортежи из 2 элементов вида `("message regexp", WarningCategory)` в качестве позиционных аргументов. Если указан один или несколько *filters*, или если необязательный ключевой аргумент *quiet* равен [`False`](https://python-all.ru/2.7/library/constants.html#False), он проверяет, что предупреждения соответствуют ожидаемым: каждый указанный фильтр должен совпадать хотя бы с одним предупреждением, вызванным вложенным кодом, иначе тест завершается неудачей; если возникают предупреждения, не совпадающие ни с одним из указанных фильтров, тест также завершается неудачей. Чтобы отключить первую из этих проверок, установите *quiet* в [`True`](https://python-all.ru/2.7/library/constants.html#True).196197Если аргументы не указаны, по умолчанию используется:198199```python200check_warnings(("", Warning), quiet=True)201```202203В этом случае перехватываются все предупреждения и исключения не возбуждаются.204205При входе в менеджер контекста возвращается экземпляр `WarningRecorder`. Базовый список предупреждений из [`catch_warnings()`](https://python-all.ru/2.7/library/warnings.html#warnings.catch_warnings) доступен через атрибут [`warnings`](https://python-all.ru/2.7/library/warnings.html#module-warnings) объекта recorder. Для удобства атрибуты объекта, представляющего последнее предупреждение, также можно получить напрямую через объект recorder (см. пример ниже). Если предупреждений не было, то любой из атрибутов, которые обычно ожидаются у объекта, представляющего предупреждение, вернёт [`None`](https://python-all.ru/2.7/library/constants.html#None).206207Объект recorder также имеет метод `reset()`, который очищает список предупреждений.208209Менеджер контекста предназначен для использования следующим образом:210211```python212with check_warnings(("assertion is always true", SyntaxWarning),213                    ("", UserWarning)):214    exec('assert(False, "Hey!")')215    warnings.warn(UserWarning("Hide me!"))216```217218В этом случае, если какое-либо из предупреждений не было возбуждено, или было возбуждено другое предупреждение, [`check_warnings()`](https://python-all.ru/2.7/library/test.html#test.support.check_warnings) возбудит исключение.219220Когда тесту требуется более глубоко изучить предупреждения, а не просто проверить, были ли они, можно использовать такой код:221222```python223with check_warnings(quiet=True) as w:224    warnings.warn("foo")225    assert str(w.args[0]) == "foo"226    warnings.warn("bar")227    assert str(w.args[0]) == "bar"228    assert str(w.warnings[0].args[0]) == "foo"229    assert str(w.warnings[1].args[0]) == "bar"230    w.reset()231    assert len(w.warnings) == 0232```233234Здесь будут перехвачены все предупреждения, и тестовый код напрямую проверяет перехваченные предупреждения.235236Новое в версии 2.6.237238Изменено в версии 2.7: Новые необязательные аргументы *filters* и *quiet*.239240#### `test.support.check_py3k_warnings(*filters, quiet=False)`241242Аналогично [`check_warnings()`](https://python-all.ru/2.7/library/test.html#test.support.check_warnings), но для предупреждений совместимости с Python 3. Если `sys.py3kwarning == 1`, проверяется, было ли предупреждение фактически вызвано. Если `sys.py3kwarning == 0`, проверяется, что предупреждение не было вызвано. Функция принимает кортежи из двух элементов вида `("message regexp", WarningCategory)` в качестве позиционных аргументов. Когда необязательный именованный аргумент *quiet* равен [`True`](https://python-all.ru/2.7/library/constants.html#True), она не считает ошибкой, если фильтр не поймал ничего. Без аргументов по умолчанию она равна:243244```python245check_py3k_warnings(("", DeprecationWarning), quiet=False)246```247248Новое в версии 2.7.249250#### `test.support.captured_stdout()`251252Это контекстный менеджер, который выполняет тело оператора [`with`](https://python-all.ru/2.7/reference/compound_stmts.html#with), используя объект [`StringIO.StringIO`](https://python-all.ru/2.7/library/stringio.html#StringIO.StringIO) в качестве sys.stdout. Этот объект можно получить с помощью предложения `as` оператора [`with`](https://python-all.ru/2.7/reference/compound_stmts.html#with).253254Пример использования:255256```python257with captured_stdout() as s:258    print "hello"259assert s.getvalue() == "hello\n"260```261262Новое в версии 2.6.263264#### `test.support.import_module(name, deprecated=False)`265266Эта функция импортирует и возвращает указанный модуль. В отличие от обычного импорта, эта функция вызывает [`unittest.SkipTest`](https://python-all.ru/2.7/library/unittest.html#unittest.SkipTest), если модуль не удаётся импортировать.267268Сообщения об устаревании модулей и пакетов подавляются во время этого импорта, если *устарело* равен [`True`](https://python-all.ru/2.7/library/constants.html#True).269270Новое в версии 2.7.271272#### `test.support.import_fresh_module(name, fresh=(), blocked=(), deprecated=False)`273274Эта функция импортирует и возвращает свежую копию указанного модуля Python, удаляя его из `sys.modules` перед импортом. Обратите внимание, что, в отличие от [`reload()`](https://python-all.ru/2.7/library/functions.html#reload), оригинальный модуль не затрагивается этой операцией.275276*fresh* – это итерируемый объект с дополнительными именами модулей, которые также удаляются из кеша `sys.modules` перед импортом.277278*blocked* – это итерируемый объект с именами модулей, которые заменяются на `0` в кеше модулей во время импорта, чтобы попытки их импортировать вызывали [`ImportError`](https://python-all.ru/2.7/library/exceptions.html#exceptions.ImportError).279280Указанный модуль и все модули, перечисленные в параметрах *fresh* и *blocked*, сохраняются перед началом импорта, а затем возвращаются обратно в `sys.modules` после завершения свежего импорта.281282Сообщения об устаревании модулей и пакетов подавляются во время этого импорта, если *устарело* равен [`True`](https://python-all.ru/2.7/library/constants.html#True).283284Эта функция вызовет [`unittest.SkipTest`](https://python-all.ru/2.7/library/unittest.html#unittest.SkipTest), если указанный модуль не удастся импортировать.285286Пример использования:287288```python289# Получить копии модуля warnings для тестирования без290# влияния на версию, используемую остальной частью тестового набора291# Одна копия использует реализацию на C, другая вынуждена использовать292# резервную реализацию на чистом Python293py_warnings = import_fresh_module('warnings', blocked=['_warnings'])294c_warnings = import_fresh_module('warnings', fresh=['_warnings'])295```296297Новое в версии 2.7.298299Модуль [`test.support`](https://python-all.ru/2.7/library/test.html#module-test.support) определяет следующие классы:300301#### `class test.support.TransientResource(exc[, **kwargs])`302303Экземпляры являются контекстным менеджером, который возбуждает [`ResourceDenied`](https://python-all.ru/2.7/library/test.html#test.support.ResourceDenied), если возникает указанный тип исключения. Все именованные аргументы трактуются как пары атрибут/значение для сравнения с любым исключением, возникшим внутри оператора [`with`](https://python-all.ru/2.7/reference/compound_stmts.html#with). Только если все пары правильно совпадают с атрибутами исключения, возбуждается [`ResourceDenied`](https://python-all.ru/2.7/library/test.html#test.support.ResourceDenied).304305Новое в версии 2.6.306307#### `class test.support.EnvironmentVarGuard`308309Класс, используемый для временной установки или отмены переменных окружения. Экземпляры можно использовать как контекстный менеджер, и они имеют полный интерфейс словаря для запроса/изменения базового `os.environ`. После выхода из контекстного менеджера все изменения переменных окружения, сделанные через этот экземпляр, будут отменены.310311Новое в версии 2.6.312313Изменено в версии 2.7: Добавлен интерфейс словаря.314315#### `EnvironmentVarGuard.set(envvar, value)`316317Временно устанавливает переменную окружения `envvar` в значение `value`.318319#### `EnvironmentVarGuard.unset(envvar)`320321Временно удаляет переменную окружения `envvar`.322323#### `class test.support.WarningsRecorder`324325Класс, используемый для записи предупреждений в модульных тестах. Подробнее см. документацию [`check_warnings()`](https://python-all.ru/2.7/library/test.html#test.support.check_warnings) выше.326327Новое в версии 2.6.328