0 added
0 removed
Original
2026-01-01
Modified
2026-02-26
1
<h2>Введение</h2>
1
<h2>Введение</h2>
2
<p>Инструменты для тестирования в Python обширны. Какие-то из них легко внедряются в код, какие-то нет. Сегодня мы познакомимся с новым инструментом - doctest. Этот с натяжкой попадает под категорию - модульное тестирование. Можно применять для тестирования как функций, так и классов.</p>
2
<p>Инструменты для тестирования в Python обширны. Какие-то из них легко внедряются в код, какие-то нет. Сегодня мы познакомимся с новым инструментом - doctest. Этот с натяжкой попадает под категорию - модульное тестирование. Можно применять для тестирования как функций, так и классов.</p>
3
<h2>О doctest</h2>
3
<h2>О doctest</h2>
4
<p>doctest интересен тем, что использование выглядит, как будто пишем код в REPL.</p>
4
<p>doctest интересен тем, что использование выглядит, как будто пишем код в REPL.</p>
5
<p>Функция factorial - для вычисления факториала. Использование функции такое:</p>
5
<p>Функция factorial - для вычисления факториала. Использование функции такое:</p>
6
<p>В результате вызова:</p>
6
<p>В результате вызова:</p>
7
<p>И здесь на арену выходит doctest. Модуль ищет фрагменты текста, которые выглядят как интерактивные python сессии. Далее выполняет сеансы и проверяет, совпадает ли с тем что указано в docstring.</p>
7
<p>И здесь на арену выходит doctest. Модуль ищет фрагменты текста, которые выглядят как интерактивные python сессии. Далее выполняет сеансы и проверяет, совпадает ли с тем что указано в docstring.</p>
8
<p>В принципе на этом можно и закончить урок - пишем в докстроках код из REPL и тест готов. Doctest прямо в чистую выполняет код из докстрок, а значит можно городить сложную логику.</p>
8
<p>В принципе на этом можно и закончить урок - пишем в докстроках код из REPL и тест готов. Doctest прямо в чистую выполняет код из докстрок, а значит можно городить сложную логику.</p>
9
<p>Несколько распространенных способов использования doctest:</p>
9
<p>Несколько распространенных способов использования doctest:</p>
10
<ul><li>Проверить, что документация к функциям отражает суть и не устарела.</li>
10
<ul><li>Проверить, что документация к функциям отражает суть и не устарела.</li>
11
<li>Для выполнения регрессионного тестирования, убедившись, что интерактивные примеры из тестового файла или тест-объект работает, как ожидалось.</li>
11
<li>Для выполнения регрессионного тестирования, убедившись, что интерактивные примеры из тестового файла или тест-объект работает, как ожидалось.</li>
12
<li>Писать учебник документации для пакета, обильно иллюстрированный примерами ввода-вывода.</li>
12
<li>Писать учебник документации для пакета, обильно иллюстрированный примерами ввода-вывода.</li>
13
</ul><p>Стоит рассмотреть несколько примеров использования.</p>
13
</ul><p>Стоит рассмотреть несколько примеров использования.</p>
14
<h2>Doctest для функций</h2>
14
<h2>Doctest для функций</h2>
15
<p>Для примера рассмотрим такой код:</p>
15
<p>Для примера рассмотрим такой код:</p>
16
<p>Функция вычисляет факториал в цикле. В блоке с docstring заметно и описание функции, и конструкции похожие на строки кода из REPL. Даже не похожие, а прямо они! Это основная особенность doctest - прямо в документации пишешь тесты. Что может быть проще? А, ну да, надо документацию писать.</p>
16
<p>Функция вычисляет факториал в цикле. В блоке с docstring заметно и описание функции, и конструкции похожие на строки кода из REPL. Даже не похожие, а прямо они! Это основная особенность doctest - прямо в документации пишешь тесты. Что может быть проще? А, ну да, надо документацию писать.</p>
17
<p>В примере простые вызовы функций да и получение исключений.</p>
17
<p>В примере простые вызовы функций да и получение исключений.</p>
18
<p>Честно и без обмана. Чтобы убедиться что тесты работают, выполняем:</p>
18
<p>Честно и без обмана. Чтобы убедиться что тесты работают, выполняем:</p>
19
<p>Тесты пройдены. Функция работает! Использование doctest крайне легкое и это определяет простоту внедрения.</p>
19
<p>Тесты пройдены. Функция работает! Использование doctest крайне легкое и это определяет простоту внедрения.</p>
20
<h2>Debug doctest</h2>
20
<h2>Debug doctest</h2>
21
<p>Дебажить такие тесты совсем просто и делается двумя путями:</p>
21
<p>Дебажить такие тесты совсем просто и делается двумя путями:</p>
22
<ul><li>писать код в REPL, что самое лучшее - сразу копируешь код в строки документации.</li>
22
<ul><li>писать код в REPL, что самое лучшее - сразу копируешь код в строки документации.</li>
23
<li>воспользоваться функцией doctest.script_from_examples:</li>
23
<li>воспользоваться функцией doctest.script_from_examples:</li>
24
</ul><h2>Тесты классов</h2>
24
</ul><h2>Тесты классов</h2>
25
<p>Тестировать функции легче и редко вызывает сложности. А вот с классами... Рассмотрим класс:</p>
25
<p>Тестировать функции легче и редко вызывает сложности. А вот с классами... Рассмотрим класс:</p>
26
<p>Типичный класс, принимает аргументы в конструктор и есть какие-то методы, которые работают с этими данными. Как такое тестировать? Да не сложнее функций:</p>
26
<p>Типичный класс, принимает аргументы в конструктор и есть какие-то методы, которые работают с этими данными. Как такое тестировать? Да не сложнее функций:</p>
27
<p>Что мы тут видим - в docstring такой же код из REPL как и для функций.</p>
27
<p>Что мы тут видим - в docstring такой же код из REPL как и для функций.</p>
28
<p>А вот пример выполнения теста:</p>
28
<p>А вот пример выполнения теста:</p>
29
<p>Доказал, что для простого класса и функций тестирование слабо отличается?</p>
29
<p>Доказал, что для простого класса и функций тестирование слабо отличается?</p>
30
<h2>Много тестов - много проблем?</h2>
30
<h2>Много тестов - много проблем?</h2>
31
<p>Очевидный недостаток doctest - когда тестов становится много, то неудобно писать в docstring. Рекомендуется выносить в отдельный файл.</p>
31
<p>Очевидный недостаток doctest - когда тестов становится много, то неудобно писать в docstring. Рекомендуется выносить в отдельный файл.</p>
32
<p>Для такого тестирования в doctest есть функция:</p>
32
<p>Для такого тестирования в doctest есть функция:</p>
33
<p>В test.txt помещаете текст из docstring. Например так:</p>
33
<p>В test.txt помещаете текст из docstring. Например так:</p>
34
<p>Тестирование функции mult(a,b) >>> from test_in_other_file import mult >>> mult(2,3) 6</p>
34
<p>Тестирование функции mult(a,b) >>> from test_in_other_file import mult >>> mult(2,3) 6</p>
35
<h2>Выводы</h2>
35
<h2>Выводы</h2>
36
<p>По сравнению с классическими юнит-тестами, у доктестов есть как плюсы:</p>
36
<p>По сравнению с классическими юнит-тестами, у доктестов есть как плюсы:</p>
37
<ul><li>простота написания тестов - можно скопировать прямо из REPL</li>
37
<ul><li>простота написания тестов - можно скопировать прямо из REPL</li>
38
<li>документация всегда соответствует коду</li>
38
<li>документация всегда соответствует коду</li>
39
</ul><p>так и минусы:</p>
39
</ul><p>так и минусы:</p>
40
<ul><li>сложный код быстро становится не читаемым</li>
40
<ul><li>сложный код быстро становится не читаемым</li>
41
<li>текстовый редактор не подсветит такой код,</li>
41
<li>текстовый редактор не подсветит такой код,</li>
42
<li>статический анализатор не найдет в нем ошибок</li>
42
<li>статический анализатор не найдет в нем ошибок</li>
43
<li>подходит не для всех функций</li>
43
<li>подходит не для всех функций</li>
44
</ul><p>Впрочем, ничто не мешает применять докстесты для мелких очевидных вещей (как в примере), и юнит-тесты для более сложных задач.</p>
44
</ul><p>Впрочем, ничто не мешает применять докстесты для мелких очевидных вещей (как в примере), и юнит-тесты для более сложных задач.</p>