> **Источник:** https://python-all.ru/3.0/library/test.html
>
> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.

---

# `test` – пакет регрессионных тестов для Python

Пакет `test` содержит все регрессионные тесты для Python, а также модули `test.test_support` и `test.regrtest`. `test.test_support` используется для расширения возможностей тестов, в то время как `test.regrtest` управляет тестовым набором.

Каждый модуль в пакете `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`; такой стиль считается устаревшим.

> **См. также**
>
> **Модуль [`unittest`](https://python-all.ru/3.0/library/unittest.html#module-unittest)**
>
> Написание регрессионных тестов PyUnit.
>
> **Модуль [`doctest`](https://python-all.ru/3.0/library/doctest.html#module-doctest)**
>
> Тесты, встроенные в строки документации.

## Написание модульных тестов для пакета `test`

Рекомендуется, чтобы тесты, использующие модуль [`unittest`](https://python-all.ru/3.0/library/unittest.html#module-unittest), следовали нескольким рекомендациям. Одна из них – называть тестовый модуль, начиная его с `test_` и заканчивая именем тестируемого модуля. Методы тестирования в тестовом модуле должны начинаться с `test_` и заканчиваться описанием того, что тестирует метод. Это необходимо, чтобы драйвер тестов распознавал методы как тестовые. Кроме того, не следует включать строку документации для метода. Вместо этого следует использовать комментарий (например, `# Тестирует функция возвращает только True или False`) для документирования тестовых методов. Это сделано потому, что строки документации выводятся на печать, если они существуют, и, таким образом, не указывается, какой именно тест выполняется.

Часто используется стандартная заготовка:

```python
import unittest
from test import test_support

class MyTestCase1(unittest.TestCase):

    # Only use setUp() and tearDown() if necessary

    def setUp(self):
        ... code to execute in preparation for tests ...

    def tearDown(self):
        ... code to execute to clean up after tests ...

    def test_feature_one(self):
        # Test feature one.
        ... testing code ...

    def test_feature_two(self):
        # Test feature two.
        ... testing code ...

    ... more test methods ...

class MyTestCase2(unittest.TestCase):
    ... same structure as MyTestCase1 ...

... more test classes ...

def test_main():
    test_support.run_unittest(MyTestCase1,
                              MyTestCase2,
                              ... list other tests ...
                             )

if __name__ == '__main__':
    test_main()
```

Этот шаблонный код позволяет запускать тестовый набор как с помощью `test.regrtest`, так и самостоятельно в качестве скрипта.

Цель регрессионного тестирования – попытаться сломать код. Это приводит к нескольким правилам, которым следует следовать:

- Набор тестов должен проверять все классы, функции и константы. Это включает не только внешний API, который будет представлен внешнему миру, но и «приватный» код.
- Предпочтение отдается тестированию «белого ящика» (анализ тестируемого кода при написании тестов). Тестирование «черного ящика» (тестирование только опубликованного пользовательского интерфейса) недостаточно полно, чтобы убедиться, что все граничные и крайние случаи протестированы.
- Убедитесь, что проверены все возможные значения, включая недопустимые. Это гарантирует, что не только все корректные значения принимаются, но и неправильные значения обрабатываются корректно.
- Исчерпайте как можно больше путей выполнения кода. Тестируйте места ветвления и соответственно подбирайте входные данные, чтобы гарантировать, что проходит как можно больше различных путей.
- Добавляйте явные тесты для любых ошибок, обнаруженных в тестируемом коде. Это гарантирует, что ошибка не возникнет снова, если код будет изменён в будущем.
- Убедитесь, что после тестов выполнена очистка (например, закрыты и удалены все временные файлы).
- Если тест зависит от конкретного условия операционной системы, то проверьте, что условие уже выполняется, прежде чем запускать тест.
- Импортируйте как можно меньше модулей и делайте это как можно раньше. Это минимизирует внешние зависимости тестов, а также уменьшает возможные аномальные поведения из-за побочных эффектов импорта модуля.
- Старайтесь максимально повторно использовать код. Иногда тесты различаются такими мелочами, как тип входных данных. Минимизируйте дублирование кода, создавая подкласс базового тестового класса, который задаёт входные данные:

  ```python
  class TestFuncAcceptsSequences(unittest.TestCase):

      func = mySuperWhammyFunction

      def test_func(self):
          self.func(self.arg)

  class AcceptLists(TestFuncAcceptsSequences):
      arg = [1,2,3]

  class AcceptStrings(TestFuncAcceptsSequences):
      arg = 'abc'

  class AcceptTuples(TestFuncAcceptsSequences):
      arg = (1,2,3)
  ```

> **См. также**
>
> **Разработка через тестирование**
>
> Книга Кента Бека о написании тестов до кода.

## Запуск тестов с помощью `test.regrtest`

`test.regrtest` можно использовать как скрипт для запуска набора регрессионных тестов Python. Запуск скрипта без аргументов автоматически запускает все регрессионные тесты из пакета `test`. Для этого находятся все модули пакета, имена которых начинаются с `test_`, они импортируются, и выполняется функция `test_main()`, если она присутствует. Имена тестов для запуска также можно передать скрипту. Указание одного регрессионного теста (**python regrtest.py** *test\_spam.py*) минимизирует вывод и покажет только, пройден тест или нет, тем самым уменьшая объём вывода.

Запуск `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).

Некоторые другие способы выполнения регрессионных тестов зависят от платформы. В Unix можно выполнить **make** *test* в каталоге верхнего уровня, где была собрана Python. В Windows запуск **rt.bat** из каталога `PCBuild` запустит все регрессионные тесты.

# `test.support` – Вспомогательные функции для тестов

Модуль `test.support` предоставляет поддержку для регрессионных тестов Python.

В этом модуле определены следующие исключения:

#### `[test.support.TestFailed]exception test.support.TestFailed`

Исключение, возбуждаемое при сбое теста. Это устарело в пользу тестов на основе

[`unittest`](https://python-all.ru/3.0/library/unittest.html#module-unittest)

и методов утверждений

[`unittest.TestCase`](https://python-all.ru/3.0/library/unittest.html#unittest.TestCase)

.

#### `[test.support.TestSkipped]exception test.support.TestSkipped`

Подкласс

[`TestFailed`](https://python-all.ru/3.0/library/test.html#test.support.TestFailed)

. Возникает, когда тест пропускается. Это происходит, когда необходимый ресурс (например, сетевое соединение) недоступен на момент тестирования.

#### `[test.support.ResourceDenied]exception test.support.ResourceDenied`

Подкласс

[`TestSkipped`](https://python-all.ru/3.0/library/test.html#test.support.TestSkipped)

. Возникает, когда ресурс (например, сетевое соединение) недоступен. Вызывается функцией

[`requires()`](https://python-all.ru/3.0/library/test.html#test.support.requires)

.

Модуль `test.support` определяет следующие константы:

#### `[test.support.verbose]test.support.verbose`

[`True`](https://python-all.ru/3.0/library/constants.html#True)

, если включён подробный вывод. Следует проверять, когда требуется более детальная информация о выполняющемся тесте.

*verbose*

устанавливается

`test.regrtest`

.

#### `[test.support.is_jython]test.support.is_jython`

[`True`](https://python-all.ru/3.0/library/constants.html#True)

, если текущий интерпретатор – Jython.

#### `[test.support.TESTFN]test.support.TESTFN`

Устанавливается в путь, по которому может быть создан временный файл. Любой созданный временный файл должен быть закрыт и удалён.

Модуль `test.support` определяет следующие функции:

#### `[test.support.forget]test.support.forget(module_name)`

Удаляет модуль с именем

*module\_name*

из

`sys.modules`

и удаляет любые откомпилированные файлы этого модуля.

#### `[test.support.is_resource_enabled]test.support.is_resource_enabled(resource)`

Возвращает

[`True`](https://python-all.ru/3.0/library/constants.html#True)

, если

*resource*

включён и доступен. Список доступных ресурсов устанавливается только тогда, когда

`test.regrtest`

выполняет тесты.

#### `[test.support.requires]test.support.requires(resource[, msg])`

Вызывает

[`ResourceDenied`](https://python-all.ru/3.0/library/test.html#test.support.ResourceDenied)

, если

*resource*

недоступен.

*msg*

является аргументом для

[`ResourceDenied`](https://python-all.ru/3.0/library/test.html#test.support.ResourceDenied)

, если он вызывается. Всегда возвращает true, если вызывается функцией,

`__name__`

которой равно

`'__main__'`

. Используется, когда тесты выполняются с помощью

`test.regrtest`

.

#### `[test.support.findfile]test.support.findfile(filename)`

Возвращает путь к файлу с именем

*filename*

. Если совпадение не найдено, возвращается

*filename*

. Это не считается ошибкой, поскольку это может быть путь к файлу.

#### `[test.support.run_unittest]test.support.run_unittest(*classes)`

Выполняет подклассы [`unittest.TestCase`](https://python-all.ru/3.0/library/unittest.html#unittest.TestCase), переданные в функцию. Функция сканирует классы на наличие методов, начинающихся с префикса `test_`, и выполняет тесты по отдельности.

Также допускается передача строк в качестве параметров; они должны быть ключами в `sys.modules`. Каждый соответствующий модуль будет просканирован с помощью `unittest.TestLoader.loadTestsFromModule()`. Обычно это встречается в следующей функции `test_main()`:

```python
def test_main():
    test_support.run_unittest(__name__)
```

Это запустит все тесты, определенные в указанном модуле.

#### `[test.support.check_warnings]test.support.check_warnings()`

Удобная обёртка для `warnings.catch_warnings()`, которая упрощает проверку того, что предупреждение было правильно вызвано с помощью одной проверки. Она примерно эквивалентна вызову `warnings.catch_warnings(record=True)`.

Основное отличие в том, что при входе в менеджер контекста возвращается экземпляр `WarningRecorder`, а не простой список. Базовый список предупреждений доступен через атрибут `warnings` объекта-регистратора, а атрибуты последнего вызванного предупреждения также доступны напрямую через этот объект. Если ни одного предупреждения не было вызвано, то все эти атрибуты будут равны [`None`](https://python-all.ru/3.0/library/constants.html#None).

На объекте-регистраторе также предоставляется метод `reset()`. Этот метод просто очищает список предупреждений.

Менеджер контекста используется следующим образом:

```python
with check_warnings() as w:
    warnings.simplefilter("always")
    warnings.warn("foo")
    assert str(w.message) == "foo"
    warnings.warn("bar")
    assert str(w.message) == "bar"
    assert str(w.warnings[0].message) == "foo"
    assert str(w.warnings[1].message) == "bar"
    w.reset()
    assert len(w.warnings) == 0
```

#### `[test.support.captured_stdout]test.support.captured_stdout()`

Это менеджер контекста, который выполняет тело оператора [`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).

Пример использования:

```python
with captured_stdout() as s:
    print("hello")
assert s.getvalue() == "hello"
```

Модуль `test.support` определяет следующие классы:

#### `[test.support.TransientResource]class test.support.TransientResource(exc[, **kwargs])`

Экземпляры представляют собой менеджер контекста, который генерирует исключение

[`ResourceDenied`](https://python-all.ru/3.0/library/test.html#test.support.ResourceDenied)

, если возникает указанный тип исключения. Все именованные аргументы обрабатываются как пары атрибут/значение для сравнения с любым исключением, возникшим внутри блока

[`with`](https://python-all.ru/3.0/reference/compound_stmts.html#with)

. Исключение

[`ResourceDenied`](https://python-all.ru/3.0/library/test.html#test.support.ResourceDenied)

возбуждается только в том случае, если все пары правильно совпадают с атрибутами исключения.

#### `[test.support.EnvironmentVarGuard]class test.support.EnvironmentVarGuard`

Класс, используемый для временной установки или снятия переменных окружения. Экземпляры можно использовать как менеджер контекста.

#### `[test.support.EnvironmentVarGuard.set]EnvironmentVarGuard.set(envvar, value)`

Временно устанавливает переменную окружения

`envvar`

в значение

`value`

.

#### `[test.support.EnvironmentVarGuard.unset]EnvironmentVarGuard.unset(envvar)`

Временно сбрасывает переменную окружения

`envvar`

.

#### `[test.support.WarningsRecorder]class test.support.WarningsRecorder`

Класс, используемый для записи предупреждений в модульных тестах. Дополнительные сведения см. в описании

[`check_warnings()`](https://python-all.ru/3.0/library/test.html#test.support.check_warnings)

выше.
