Инфраструктура модульного тестирования для модуля Python - PullRequest
8 голосов
/ 14 июля 2010

Я пишу модуль на Python и хотел бы протестировать его.Я новичок в Python и несколько озадачен доступными опциями.

В настоящее время я хотел бы написать свои тесты как doctests , поскольку мне нравится декларативный, а не императивный стиль (однако, не стесняйтесьотвлечь меня от этого предпочтения, если оно дезинформировано).Однако возникает несколько вопросов:

  1. Где я должен поставить тесты?В том же файле, что и код, который они тестируют (или в docstrings для doctests)?Или лучше разделить их в отдельный каталог?
  2. Как можно выполнить все тесты всего модуля из командной строки за один раз?
  3. Как я могу сообщитьохват кода набора тестов?
  4. Какие-либо другие рекомендации, которые мне следует знать для модульного тестирования в python?

Ответы [ 6 ]

12 голосов
/ 14 июля 2010

не стесняйтесь разубедить меня в этом предпочтении, если оно дезинформировано

Я считаю, что я использовал doctest более широко ( способ , расширяющий границы предполагаемого использования)чем любой другой разработчик с открытым исходным кодом, по крайней мере, в рамках одного проекта - все тесты в моем проекте gmpy являются тестами.Он был совершенно новым в то время, когда начинался gmpy, это казалось маленьким трюком, и если что-то стоит делать, то стоит делать в избытке - верно? -)

Неверно.За исключением gmpy, где переделывать все как надлежащие юнит-тесты было бы слишком большой переработкой, я никогда больше не повторял эту ошибку: в наши дни я использую юнит-тесты в качестве юнит-тестов и проверяю документы просто для проверки своих документов, посколькуМы всегда были предназначены для использования.То, что делают тесты (сравнивают ожидаемый результат с реальным результатом на равенство - вот и все), просто не является хорошей или надежной основой для построения надежного набора тестов.Это никогда не было задумано иначе.

Я бы порекомендовал вам взглянуть на нос .Модуль unittest в новом Python 2.7 намного богаче и приятнее, и если вы застряли на 2.4, 2.5 или 2.6, вы все равно можете использовать новые функции с unittest2 , который вы можете загрузить и установить;nose неплохо дополняет unittest.

Если вы не можете выдержать юниттест (но - попробуйте, он вырастет на вас! -), возможно, попробуйте py.test , альтернативный пакет с совершенно другой философией.

Но, , пожалуйста , не растягивайте doctest, чтобы протестировать что-либо, кроме примеров в документации!Сравнение с точным равенством будет стоять у вас на пути слишком часто, так как мне пришлось учиться за мой (метафорический ;-) расход в gmpy ...

3 голосов
/ 14 июля 2010

Мне не нравятся тесты по этим причинам:

  • Вы не можете запустить подмножество тестов. Если тест не пройден, полезно запустить только один тест. Doctest не предоставляет возможности сделать это.
  • Если сбой произошел в середине doctest, все это останавливается. Я бы лучше посмотрел все результаты, чтобы решить, как справиться с поломкой.
  • Стиль кодирования стилизован и должен иметь результаты для печати. ​​
  • Ваш код выполняется особым образом, поэтому сложнее рассуждать о том, как он будет выполняться, сложнее добавлять помощников и труднее программировать вокруг тестов.

Этот список был взят из моего поста в блоге Вещи, которые мне не нравятся в doctest , где есть еще и длинная цепочка комментариев, обсуждающих пункты.

Об освещении: я не верю, что есть инструмент покрытия для Python, который будет измерять охват в рамках doctests. Но поскольку это просто длинные списки операторов без ветвей или петель, это проблема?

2 голосов
/ 14 июля 2010

У меня есть подозрение, что Алекс может быть немного впереди меня на кривой программиста, но если вам нужна перспектива кого-то с некоторым опытом работы с Python (как «пользователь», а не как эксперт или евангелист), но нев той же лиге мои выводы о модульном тестировании были почти такими же.

Doctests может показаться отличным для простого тестирования в начале, и я пошел в этом направлении для какого-то личного проекта дома, потому что он былрекомендуется в другом месте.На работе мы используем нос (хотя он был таким консервированным и завернутым, у меня сложилось впечатление, что мы использовали pyUnit совсем недавно), и несколько месяцев назад я тоже перешел к носу дома.

время настройки и накладные расходы на управление, а также отделение от реального кода, вначале могут показаться ненужными, особенно когда вы тестируете что-то не очень большое, но в долгосрочной перспективе я обнаружил, что в тестах появляютсяспособ каждого рефакторинга или реструктуризации, который я хотел сделать, довольно сложно поддерживать, практически невозможно масштабировать и очень быстро компенсировать первоначальную экономию.И да, я знаю, что модульное тестирование - это не то же самое, что интеграционное тестирование, но doctests обычно определяет ваши юниты для вас слишком строго.Они также не очень подходят для гибкой разработки на основе юнитов, если вы когда-нибудь решите, что это правильный инструмент для рисования или модель разработки.

Вам может потребоваться немного времени, чтобы спланировать, а затем усовершенствовать свои юнит-тесты, как pyUnit или управление носомвы к, но есть вероятность, что даже в краткосрочной перспективе вы обнаружите, что это действительно помогает вам на многих уровнях.Я знаю, что это помогло мне, и я относительно плохо знаком со сложностью и масштабностью кодовой базы, над которой я сейчас работаю.Просто нужно стиснуть зубы в течение первых нескольких недель.

1 голос
/ 14 июля 2010

doctests отлично подходят для быстрых, второстепенных модульных тестов, которые описывают, каковы некоторые из основных способов использования рассматриваемых объектов (как они отображаются в строках документации, и, следовательно, помогают (что угодно) и т. Д.).

Лично я обнаружил, что расширенное и более тщательное тестирование более эффективно с использованием модуля unittest, и теперь модуль 2.7 (обратно перенесенный на unittest2) имеет еще более удобные утверждения. Вы можете настроить наборы тестов и любой сложный сценарий так, как вам нравится, с помощью среды модульного тестирования и охватить целые серии различных тестов за один раз (в командной строке)

cover.py , автором которого является Нед Бэтчелдер, и, как упоминает @bstpierre, будет работать с любым из них, и я рекомендую его посмотреть, что вы тестировали в коде, а что нет. Вы можете добавить его в CI-систему (например, Hudson или что-либо еще, что вам нравится использовать), чтобы быть в курсе того, что покрыто и нет, а HTML-отчеты являются фантастическими для просмотра того, что не было затронуто тестированием. Coverage поддерживает вывод в формате Junit xml, который многие системы CI знают, как предоставлять графики текущих результатов, чтобы вы могли видеть, как сборка улучшается или ухудшается со временем.

1 голос
/ 14 июля 2010

Для покрытия, посмотрите превосходный cover.py .

В остальном все, что написал Алекс Мартелли, очень важно.

0 голосов
/ 14 июля 2010

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

Один совет, который я могу внести, - это вызывать модульные тесты из кода, обрабатывающего __name__ == "__main__, так что еслиТестовый файл запускается как скрипт, он запускает свои тесты.

Например:

#!/usr/bin/env python

"""
Unit tests for the GetFiles.py utility
"""

import unittest
from FileUtilities import getTree

class TestFileUtilities(unittest.TestCase):

   def testGetTree(self):
      """
      Tests that a known tree is found and incidentally confirms
      that we have the tree we expected to use for our current
      sample extraction.
      """
      found = getTree('./anzmeta-dtd', '.pen')
      expected_path_tail = ['ISOdia.pen',
                       'ISOgrk1.pen',
                       'ISOtech.pen']
      for i, full_path in enumerate(found):
         assert full_path.endswith( expected_path_tail[i] ), expected_path_tail[i]

# other tests elided         

if __name__ == "__main__":
   # When this module is executed from the command-line, run all its tests
   unittest.main()
...