Python для продвинутых
2026-02-26 16:56 Diff

Введение

Инструменты для тестирования в Python обширны. Какие-то из них легко внедряются в код, какие-то нет. Сегодня мы познакомимся с новым инструментом - doctest. Этот с натяжкой попадает под категорию - модульное тестирование. Можно применять для тестирования как функций, так и классов.

О doctest

doctest интересен тем, что использование выглядит, как будто пишем код в REPL.

Функция factorial - для вычисления факториала. Использование функции такое:

В результате вызова:

И здесь на арену выходит doctest. Модуль ищет фрагменты текста, которые выглядят как интерактивные python сессии. Далее выполняет сеансы и проверяет, совпадает ли с тем что указано в docstring.

В принципе на этом можно и закончить урок - пишем в докстроках код из REPL и тест готов. Doctest прямо в чистую выполняет код из докстрок, а значит можно городить сложную логику.

Несколько распространенных способов использования doctest:

  • Проверить, что документация к функциям отражает суть и не устарела.
  • Для выполнения регрессионного тестирования, убедившись, что интерактивные примеры из тестового файла или тест-объект работает, как ожидалось.
  • Писать учебник документации для пакета, обильно иллюстрированный примерами ввода-вывода.

Стоит рассмотреть несколько примеров использования.

Doctest для функций

Для примера рассмотрим такой код:

Функция вычисляет факториал в цикле. В блоке с docstring заметно и описание функции, и конструкции похожие на строки кода из REPL. Даже не похожие, а прямо они! Это основная особенность doctest - прямо в документации пишешь тесты. Что может быть проще? А, ну да, надо документацию писать.

В примере простые вызовы функций да и получение исключений.

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

Тесты пройдены. Функция работает! Использование doctest крайне легкое и это определяет простоту внедрения.

Debug doctest

Дебажить такие тесты совсем просто и делается двумя путями:

  • писать код в REPL, что самое лучшее - сразу копируешь код в строки документации.
  • воспользоваться функцией doctest.script_from_examples:

Тесты классов

Тестировать функции легче и редко вызывает сложности. А вот с классами... Рассмотрим класс:

Типичный класс, принимает аргументы в конструктор и есть какие-то методы, которые работают с этими данными. Как такое тестировать? Да не сложнее функций:

Что мы тут видим - в docstring такой же код из REPL как и для функций.

А вот пример выполнения теста:

Доказал, что для простого класса и функций тестирование слабо отличается?

Много тестов - много проблем?

Очевидный недостаток doctest - когда тестов становится много, то неудобно писать в docstring. Рекомендуется выносить в отдельный файл.

Для такого тестирования в doctest есть функция:

В test.txt помещаете текст из docstring. Например так:

Тестирование функции mult(a,b) >>> from test_in_other_file import mult >>> mult(2,3) 6

Выводы

По сравнению с классическими юнит-тестами, у доктестов есть как плюсы:

  • простота написания тестов - можно скопировать прямо из REPL
  • документация всегда соответствует коду

так и минусы:

  • сложный код быстро становится не читаемым
  • текстовый редактор не подсветит такой код,
  • статический анализатор не найдет в нем ошибок
  • подходит не для всех функций

Впрочем, ничто не мешает применять докстесты для мелких очевидных вещей (как в примере), и юнит-тесты для более сложных задач.