( Изначально опубликовано здесь .)
Доктра является одним из моих любимых модулей Python. С доктором можно выполнить кодовые фрагменты из документации. Вы могли бы, например, написать что-то вроде этого в вашем Turorial.md
…
>>> f() 1
… а затем выполнить команду Python -MdoCtest Tutorial.md
Отказ Если f ()
Возвращает 1, ничего не произойдет. Если он возвращает что-то еще, однако появится сообщение об ошибке, похоже на это:
********************************************************************** File "f.txt", line 2, in f.txt Failed example: f() Expected: 1 Got: 2 ********************************************************************** 1 items had failures: 1 of 2 in f.txt ***Test Failed*** 1 failures.
Это впечатляющий инструмент, но и непопулярный. Проблема в том, что доктра часто используется неправильно. Например, распространено, чтобы попытаться написать тесты подразделения с доставляющими. Большая ошибка.
Тем не менее, я считаю, что несправедливо игнорировать модуль из-за этих недоразумений. Датчик может и должен быть использован для того, что он делает лучше всего: сохранить вашу документацию живой и даже вести ваше развитие!
Позвольте мне показать пример.
Когда вы не знаете, что делать
Несколько дней назад я писал класс, чтобы изменить HTML-документ, используя xml.dom.minidom
Отказ В какой-то момент мне нужна функция для отображения классов CSS к узлам из документа. Только было бы сложной функцией! Я понятия не имел, с чего начать.
Теоретически, узлы могут быть полезны здесь. Они просто не будут очень практичными: это была внутренняя, частная функция, подробность реализации. Чтобы проверить это, мне придется разоблачить это. Нам также нужен новый файл для испытаний. И тестовые случаи в любом случае не так разборчивы.
Чтение документации из будущего
Вместо этого я сначала задокументировал функцию. Я написал небольшой абзац, описывающий то, что это будет делать. Это было достаточно, чтобы уточнить мои идеи немного:
Учитывая XML.dom.minidom. Узел, возвращает карту из каждого атрибута «класса» в список узлов с помощью этого класса.
Затем я думал о том, как написать то же самое, но с примером кода. В моей голове эта функция (которую я позвонил get_css_class_dict ()
) получит xml.dom.minidom
документ. Итак, я написал пример:
>>> doc = xml.dom.minidom.parseString( ... ''' ... ... ... ... ... ... ''')
Учитывая этот фрагмент, я бы ожидал, что функция вернет дикт. Мой документ имеет два класса CSS, «A» и «B», а затем мой дикт будет иметь два ключа. Каждый ключ будет иметь список узлов с классом CSS. Что-то вроде этого:
>>> d = get_css_class_dict(doc) >>> d['a'] # doctest: +ELLIPSIS [, ] >>> d['b'] # doctest: +ELLIPSIS [ ]
Я положил эти эскизы в DOCSTRING get_css_class_dict ()
Отказ До сих пор у нас есть эта функция:
def get_css_class_dict(node): """ Given an xml.dom.minidom.Node, returns a map from every "class" attribute from it to a list of nodes with this class. For example, for the document below: >>> doc = xml.dom.minidom.parseString( ... ''' ... ... ... ... ... ... ''') ...we will get this: >>> d = get_css_class_dict(doc) >>> d['a'] # doctest: +ELLIPSIS [, ] >>> d['b'] # doctest: +ELLIPSIS [ ] """ pass
Я мог бы сделать что-то подобное с модульными тестами, но вокруг будет гораздо больше кода, загрязняя документацию. Кроме того, проза любезно дополняет Кодекс, давая ритму чтению.
Я выполняю докторы, и это результат:
********************************************************************** File "vtodo/listing/filler.py", line 75, in filler.get_css_class_dict Failed example: d['a'] Exception raised: Traceback (most recent call last): File "/usr/lib/python3.6/doctest.py", line 1330, in __run compileflags, 1), test.globs) File "", line 1, in d['a'] TypeError: 'NoneType' object is not subscriptable ********************************************************************** File "vtodo/listing/filler.py", line 77, in filler.get_css_class_dict Failed example: d['b'] Exception raised: Traceback (most recent call last): File "/usr/lib/python3.6/doctest.py", line 1330, in __run compileflags, 1), test.globs) File "File " ", line 1, in ", line 1, in d['b'] TypeError: 'NoneType' object is not subscriptable ********************************************************************** 1 items had failures: 2 of 4 in filler.get_css_class_dict ***Test Failed*** 2 failures.
Я следую в разработке тестов, в основном, но с исполняемой документацией. Сразу у меня есть читаемый пример и базовый тест.
Теперь нам просто нужно реализовать функцию! Я использовал некоторую рекурсию, и, если код не самый сжатый в первую очередь …
def get_css_class_dict(node): """ Given an xml.dom.minidom.Node, returns a map from every "class" attribute from it to a list of nodes with this class. For example, for the document below: >>> doc = xml.dom.minidom.parseString( ... ''' ... ... ... ... ... ... ''') ...we will get this: >>> d = get_css_class_dict(doc) >>> d['a'] # doctest: +ELLIPSIS [, ] >>> d['b'] # doctest: +ELLIPSIS [ ] """ css_class_dict = {} if node.attributes is not None and 'class' in node.attributes: css_classes = node.attributes['class'].value for css_class in css_classes.split(): css_class_list = css_class_dict.get(css_class, []) css_class_list.append(node) css_class_dict[css_class] = css_class_list childNodes = getattr(node, 'childNodes', []) for cn in childNodes: ccd = get_css_class_dict(cn) for css_class, nodes_list in ccd.items(): css_class_list = css_class_dict.get(css_class, []) css_class_list.extend(nodes_list) css_class_dict[css_class] = css_class_list return css_class_dict
… По крайней мере, это работает как ожидалось:
$ python -mdoctest vtodo/listing/filler.py ********************************************************************** File "vtodo/listing/filler.py", line 77, in filler.get_css_class_dict Failed example: d['b'] # doctest: +ELLIPSIS Expected: [] Got: [ ] ********************************************************************** 1 items had failures: 1 of 4 in filler.get_css_class_dict ***Test Failed*** 1 failures.
Подождите минуту. Что это было?!
Когда документация неверна
Ну, в моей докторе есть ошибка! Элемент SPAN не имеет класса «B» – элемент div. Итак, мне просто нужно изменить линию
[
к
[
И доктю пройдет.
Разве это не замечательно? Я нашел скольжение в мою документацию почти сразу. Более того: если поведение моей функции когда-нибудь меняет, пример из моего доскастрания не удастся. Я точно знаю, где документация понадобится обновления.
Сделать докуды
Это обоснование до дочисного. Наша документация имела тонкую ошибку, и мы нашли его, выполняя его. Доводы не гарантируют правильность кода; Они усиливают правильность документации. Это хорошо известный аспект пакета, но, похоже, мало кто, кажется, это стоит того.
Я думаю, что это! Документация часто считается неприятной работой, но это не должно быть так. Так же, как TDD делают тесты, захватывающие, можно сделать документацию развлечения с доставляющими.
Кроме того, таким же образом TDD может указать на ограничения дизайна, упорные сроки пишущих докторов могут указать на проблемы API. Если было трудно написать четкий и краткий пример использования для вашего API, окруженный объяснением текста, он, вероятно, слишком сложно, верно?
Доказывать шанс
В конце концов, я вижу доние бывших ограничений. Например, они обязательно неадекватны для модульных тестов. И все же, доктю делает документирование так легко и весело! Я не понимаю, почему это так непопулярно.
Тем не менее, его наибольшее преимущество – насколько доктор издает Процесс развития Полегче. Некоторое время назад я пошутил, что нам нужно создать docdd:
С доктором это не просто шутка.
Этот пост является переводом Dê UMA шанс до доктора .
Покрытие изображения от Wikimedia Commons. .
Оригинал: “https://dev.to/adambrandizzi/give-doctest-a-chance-4d2g”