Python для продвинутых
Теория: Мир Python: doctest
Введение
Инструменты для тестирования в 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
- документация всегда соответствует коду
так и минусы:
- сложный код быстро становится не читаемым
- текстовый редактор не подсветит такой код,
- статический анализатор не найдет в нем ошибок
- подходит не для всех функций
Впрочем, ничто не мешает применять докстесты для мелких очевидных вещей (как в примере), и юнит-тесты для более сложных задач.

