test.md
1> **Источник:** https://python-all.ru/3.0/library/test.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# `test` – пакет регрессионных тестов для Python89Пакет `test` содержит все регрессионные тесты для Python, а также модули `test.test_support` и `test.regrtest`. `test.test_support` используется для расширения возможностей тестов, в то время как `test.regrtest` управляет тестовым набором.1011Каждый модуль в пакете `test`, имя которого начинается с `test_`, является набором тестов для определённого модуля или функции. Все новые тесты должны быть написаны с использованием модуля [`unittest`](https://python-all.ru/3.0/library/unittest.html#module-unittest) или [`doctest`](https://python-all.ru/3.0/library/doctest.html#module-doctest). Некоторые старые тесты написаны в «традиционном» стиле, который сравнивает вывод, отправленный в `sys.stdout`; такой стиль считается устаревшим.1213> **См. также**14>15> **Модуль [`unittest`](https://python-all.ru/3.0/library/unittest.html#module-unittest)**16>17> Написание регрессионных тестов PyUnit.18>19> **Модуль [`doctest`](https://python-all.ru/3.0/library/doctest.html#module-doctest)**20>21> Тесты, встроенные в строки документации.2223## Написание модульных тестов для пакета `test`2425Рекомендуется, чтобы тесты, использующие модуль [`unittest`](https://python-all.ru/3.0/library/unittest.html#module-unittest), следовали нескольким рекомендациям. Одна из них – называть тестовый модуль, начиная его с `test_` и заканчивая именем тестируемого модуля. Методы тестирования в тестовом модуле должны начинаться с `test_` и заканчиваться описанием того, что тестирует метод. Это необходимо, чтобы драйвер тестов распознавал методы как тестовые. Кроме того, не следует включать строку документации для метода. Вместо этого следует использовать комментарий (например, `# Тестирует функция возвращает только True или False`) для документирования тестовых методов. Это сделано потому, что строки документации выводятся на печать, если они существуют, и, таким образом, не указывается, какой именно тест выполняется.2627Часто используется стандартная заготовка:2829```python30import unittest31from test import test_support3233class MyTestCase1(unittest.TestCase):3435 # Only use setUp() and tearDown() if necessary3637 def setUp(self):38 ... code to execute in preparation for tests ...3940 def tearDown(self):41 ... code to execute to clean up after tests ...4243 def test_feature_one(self):44 # Test feature one.45 ... testing code ...4647 def test_feature_two(self):48 # Test feature two.49 ... testing code ...5051 ... more test methods ...5253class MyTestCase2(unittest.TestCase):54 ... same structure as MyTestCase1 ...5556... more test classes ...5758def test_main():59 test_support.run_unittest(MyTestCase1,60 MyTestCase2,61 ... list other tests ...62 )6364if __name__ == '__main__':65 test_main()66```6768Этот шаблонный код позволяет запускать тестовый набор как с помощью `test.regrtest`, так и самостоятельно в качестве скрипта.6970Цель регрессионного тестирования – попытаться сломать код. Это приводит к нескольким правилам, которым следует следовать:7172- Набор тестов должен проверять все классы, функции и константы. Это включает не только внешний API, который будет представлен внешнему миру, но и «приватный» код.73- Предпочтение отдается тестированию «белого ящика» (анализ тестируемого кода при написании тестов). Тестирование «черного ящика» (тестирование только опубликованного пользовательского интерфейса) недостаточно полно, чтобы убедиться, что все граничные и крайние случаи протестированы.74- Убедитесь, что проверены все возможные значения, включая недопустимые. Это гарантирует, что не только все корректные значения принимаются, но и неправильные значения обрабатываются корректно.75- Исчерпайте как можно больше путей выполнения кода. Тестируйте места ветвления и соответственно подбирайте входные данные, чтобы гарантировать, что проходит как можно больше различных путей.76- Добавляйте явные тесты для любых ошибок, обнаруженных в тестируемом коде. Это гарантирует, что ошибка не возникнет снова, если код будет изменён в будущем.77- Убедитесь, что после тестов выполнена очистка (например, закрыты и удалены все временные файлы).78- Если тест зависит от конкретного условия операционной системы, то проверьте, что условие уже выполняется, прежде чем запускать тест.79- Импортируйте как можно меньше модулей и делайте это как можно раньше. Это минимизирует внешние зависимости тестов, а также уменьшает возможные аномальные поведения из-за побочных эффектов импорта модуля.80- Старайтесь максимально повторно использовать код. Иногда тесты различаются такими мелочами, как тип входных данных. Минимизируйте дублирование кода, создавая подкласс базового тестового класса, который задаёт входные данные:8182 ```python83 class TestFuncAcceptsSequences(unittest.TestCase):8485 func = mySuperWhammyFunction8687 def test_func(self):88 self.func(self.arg)8990 class AcceptLists(TestFuncAcceptsSequences):91 arg = [1,2,3]9293 class AcceptStrings(TestFuncAcceptsSequences):94 arg = 'abc'9596 class AcceptTuples(TestFuncAcceptsSequences):97 arg = (1,2,3)98 ```99100> **См. также**101>102> **Разработка через тестирование**103>104> Книга Кента Бека о написании тестов до кода.105106## Запуск тестов с помощью `test.regrtest`107108`test.regrtest` можно использовать как скрипт для запуска набора регрессионных тестов Python. Запуск скрипта без аргументов автоматически запускает все регрессионные тесты из пакета `test`. Для этого находятся все модули пакета, имена которых начинаются с `test_`, они импортируются, и выполняется функция `test_main()`, если она присутствует. Имена тестов для запуска также можно передать скрипту. Указание одного регрессионного теста (**python regrtest.py** *test\_spam.py*) минимизирует вывод и покажет только, пройден тест или нет, тем самым уменьшая объём вывода.109110Запуск `test.regrtest` напрямую позволяет установить, какие ресурсы доступны для использования тестами. Это делается с помощью опции командной строки [*-u*](https://python-all.ru/3.0/using/cmdline.html#cmdoption-u). Выполните **python regrtest.py** *-uall*, чтобы включить все ресурсы; указание *all* в качестве параметра для [*-u*](https://python-all.ru/3.0/using/cmdline.html#cmdoption-u) включает все возможные ресурсы. Если нужны все ресурсы, кроме одного (более типичный случай), после *all* можно перечислить через запятую ресурсы, которые не нужны. Команда **python regrtest.py** *-uall,-audio,-largefile* запустит `test.regrtest` со всеми ресурсами, кроме *audio* и *largefile*. Чтобы увидеть список всех ресурсов и дополнительные опции командной строки, выполните **python regrtest.py** [*-h*](https://python-all.ru/3.0/using/cmdline.html#cmdoption-h).111112Некоторые другие способы выполнения регрессионных тестов зависят от платформы. В Unix можно выполнить **make** *test* в каталоге верхнего уровня, где была собрана Python. В Windows запуск **rt.bat** из каталога `PCBuild` запустит все регрессионные тесты.113114# `test.support` – Вспомогательные функции для тестов115116Модуль `test.support` предоставляет поддержку для регрессионных тестов Python.117118В этом модуле определены следующие исключения:119120#### `[test.support.TestFailed]exception test.support.TestFailed`121122Исключение, возбуждаемое при сбое теста. Это устарело в пользу тестов на основе123124[`unittest`](https://python-all.ru/3.0/library/unittest.html#module-unittest)125126и методов утверждений127128[`unittest.TestCase`](https://python-all.ru/3.0/library/unittest.html#unittest.TestCase)129130.131132#### `[test.support.TestSkipped]exception test.support.TestSkipped`133134Подкласс135136[`TestFailed`](https://python-all.ru/3.0/library/test.html#test.support.TestFailed)137138. Возникает, когда тест пропускается. Это происходит, когда необходимый ресурс (например, сетевое соединение) недоступен на момент тестирования.139140#### `[test.support.ResourceDenied]exception test.support.ResourceDenied`141142Подкласс143144[`TestSkipped`](https://python-all.ru/3.0/library/test.html#test.support.TestSkipped)145146. Возникает, когда ресурс (например, сетевое соединение) недоступен. Вызывается функцией147148[`requires()`](https://python-all.ru/3.0/library/test.html#test.support.requires)149150.151152Модуль `test.support` определяет следующие константы:153154#### `[test.support.verbose]test.support.verbose`155156[`True`](https://python-all.ru/3.0/library/constants.html#True)157158, если включён подробный вывод. Следует проверять, когда требуется более детальная информация о выполняющемся тесте.159160*verbose*161162устанавливается163164`test.regrtest`165166.167168#### `[test.support.is_jython]test.support.is_jython`169170[`True`](https://python-all.ru/3.0/library/constants.html#True)171172, если текущий интерпретатор – Jython.173174#### `[test.support.TESTFN]test.support.TESTFN`175176Устанавливается в путь, по которому может быть создан временный файл. Любой созданный временный файл должен быть закрыт и удалён.177178Модуль `test.support` определяет следующие функции:179180#### `[test.support.forget]test.support.forget(module_name)`181182Удаляет модуль с именем183184*module\_name*185186из187188`sys.modules`189190и удаляет любые откомпилированные файлы этого модуля.191192#### `[test.support.is_resource_enabled]test.support.is_resource_enabled(resource)`193194Возвращает195196[`True`](https://python-all.ru/3.0/library/constants.html#True)197198, если199200*resource*201202включён и доступен. Список доступных ресурсов устанавливается только тогда, когда203204`test.regrtest`205206выполняет тесты.207208#### `[test.support.requires]test.support.requires(resource[, msg])`209210Вызывает211212[`ResourceDenied`](https://python-all.ru/3.0/library/test.html#test.support.ResourceDenied)213214, если215216*resource*217218недоступен.219220*msg*221222является аргументом для223224[`ResourceDenied`](https://python-all.ru/3.0/library/test.html#test.support.ResourceDenied)225226, если он вызывается. Всегда возвращает true, если вызывается функцией,227228`__name__`229230которой равно231232`'__main__'`233234. Используется, когда тесты выполняются с помощью235236`test.regrtest`237238.239240#### `[test.support.findfile]test.support.findfile(filename)`241242Возвращает путь к файлу с именем243244*filename*245246. Если совпадение не найдено, возвращается247248*filename*249250. Это не считается ошибкой, поскольку это может быть путь к файлу.251252#### `[test.support.run_unittest]test.support.run_unittest(*classes)`253254Выполняет подклассы [`unittest.TestCase`](https://python-all.ru/3.0/library/unittest.html#unittest.TestCase), переданные в функцию. Функция сканирует классы на наличие методов, начинающихся с префикса `test_`, и выполняет тесты по отдельности.255256Также допускается передача строк в качестве параметров; они должны быть ключами в `sys.modules`. Каждый соответствующий модуль будет просканирован с помощью `unittest.TestLoader.loadTestsFromModule()`. Обычно это встречается в следующей функции `test_main()`:257258```python259def test_main():260 test_support.run_unittest(__name__)261```262263Это запустит все тесты, определенные в указанном модуле.264265#### `[test.support.check_warnings]test.support.check_warnings()`266267Удобная обёртка для `warnings.catch_warnings()`, которая упрощает проверку того, что предупреждение было правильно вызвано с помощью одной проверки. Она примерно эквивалентна вызову `warnings.catch_warnings(record=True)`.268269Основное отличие в том, что при входе в менеджер контекста возвращается экземпляр `WarningRecorder`, а не простой список. Базовый список предупреждений доступен через атрибут `warnings` объекта-регистратора, а атрибуты последнего вызванного предупреждения также доступны напрямую через этот объект. Если ни одного предупреждения не было вызвано, то все эти атрибуты будут равны [`None`](https://python-all.ru/3.0/library/constants.html#None).270271На объекте-регистраторе также предоставляется метод `reset()`. Этот метод просто очищает список предупреждений.272273Менеджер контекста используется следующим образом:274275```python276with check_warnings() as w:277 warnings.simplefilter("always")278 warnings.warn("foo")279 assert str(w.message) == "foo"280 warnings.warn("bar")281 assert str(w.message) == "bar"282 assert str(w.warnings[0].message) == "foo"283 assert str(w.warnings[1].message) == "bar"284 w.reset()285 assert len(w.warnings) == 0286```287288#### `[test.support.captured_stdout]test.support.captured_stdout()`289290Это менеджер контекста, который выполняет тело оператора [`with`](https://python-all.ru/3.0/reference/compound_stmts.html#with), используя объект `StringIO.StringIO` в качестве sys.stdout. Этот объект можно получить с помощью предложения `as` оператора [`with`](https://python-all.ru/3.0/reference/compound_stmts.html#with).291292Пример использования:293294```python295with captured_stdout() as s:296 print("hello")297assert s.getvalue() == "hello"298```299300Модуль `test.support` определяет следующие классы:301302#### `[test.support.TransientResource]class test.support.TransientResource(exc[, **kwargs])`303304Экземпляры представляют собой менеджер контекста, который генерирует исключение305306[`ResourceDenied`](https://python-all.ru/3.0/library/test.html#test.support.ResourceDenied)307308, если возникает указанный тип исключения. Все именованные аргументы обрабатываются как пары атрибут/значение для сравнения с любым исключением, возникшим внутри блока309310[`with`](https://python-all.ru/3.0/reference/compound_stmts.html#with)311312. Исключение313314[`ResourceDenied`](https://python-all.ru/3.0/library/test.html#test.support.ResourceDenied)315316возбуждается только в том случае, если все пары правильно совпадают с атрибутами исключения.317318#### `[test.support.EnvironmentVarGuard]class test.support.EnvironmentVarGuard`319320Класс, используемый для временной установки или снятия переменных окружения. Экземпляры можно использовать как менеджер контекста.321322#### `[test.support.EnvironmentVarGuard.set]EnvironmentVarGuard.set(envvar, value)`323324Временно устанавливает переменную окружения325326`envvar`327328в значение329330`value`331332.333334#### `[test.support.EnvironmentVarGuard.unset]EnvironmentVarGuard.unset(envvar)`335336Временно сбрасывает переменную окружения337338`envvar`339340.341342#### `[test.support.WarningsRecorder]class test.support.WarningsRecorder`343344Класс, используемый для записи предупреждений в модульных тестах. Дополнительные сведения см. в описании345346[`check_warnings()`](https://python-all.ru/3.0/library/test.html#test.support.check_warnings)347348выше.349