HTML Diff
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) &gt;&gt;&gt; from test_in_other_file import mult &gt;&gt;&gt; mult(2,3) 6</p>
34 <p>Тестирование функции mult(a,b) &gt;&gt;&gt; from test_in_other_file import mult &gt;&gt;&gt; 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>