Подтвердить что ты не робот

Как написать современные тесты Python?

Каков последний способ написать тесты Python? Какие модули/рамки использовать?

И еще один вопрос: есть ли doctest тесты по-прежнему какого-либо значения? Или все тесты должны быть написаны в более современной структуре тестирования?

Спасибо, Бода Сидо.

4b9b3361

Ответ 1

Обычный способ - использовать встроенный модуль unittest для создания модульных тестов и объединения их вместе для тестирования наборов, которые могут выполняться независимо, unittest очень похож на (и вдохновляется) jUnit и, следовательно, очень прост в использовании.

Если вас интересуют самые последние изменения, взгляните на новый разговор PyCon от Michael Foord:

PyCon 2010: новое и улучшенное: внесение изменений в unittest

Ответ 2

Использование встроенного модуля unittest столь же актуально и легко. Другие варианты тестирования устройства py.test, nose и twisted.trial в основном совместимы с unittest.

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

Ответ 3

Я не очень разбираюсь в доктринах, но в моем университете обучают и поощряют тестирование носа.

Нос можно установить, следуя этой процедуре (я предполагаю, что вы используете ПК - ОС Windows):

  • установить setuptools
  • Запустить командную строку DOS (Пуск → Все программы → Стандартные → Командная строка)
  • Чтобы этот шаг работал, вы должны быть подключены к Интернету. В DOS введите: C:\Python25\Scripts\easy_install нос

Если вы находитесь на другой ОС, проверьте этот сайт

ИЗМЕНИТЬ

Прошло два года с тех пор, как я изначально написал этот пост. Теперь я узнал об этом принципе программирования, называемом Проектирование по контракту. Это позволяет программисту определять предварительные условия, постусловия и инварианты (называемые контрактами) для всех функций в их коде. Эффект заключается в том, что ошибка возникает, если какой-либо из этих контрактов нарушен.

Структура DbC, которую я рекомендовал бы для python, называется PyContract Я успешно использовал ее в своем структура эволюционного программирования

Ответ 4

В моем текущем проекте я использую unittest, minimock, nose. Раньше я интенсивно использовал доктрины, но в крупных проектах некоторые тесты могут стать довольно громоздкими, поэтому я предпочитаю использовать доктрины для более простых функций.

Если вы используете setuptools или distribute (вы должны переключиться на распространение), вы можете настроить нос в качестве сборщика тестов по умолчанию, чтобы вы могли запускать ваши тесты с помощью "теста python setup.py"

setup(name='foo',
      ...
      test_suite='nose.collector',
      ...

Теперь запуск "теста python setup.py" вызовет нос, который сканирует ваш проект для вещей, которые выглядят как тесты и запускают их, накапливая результаты. Если у вас также есть доктрины в вашем проекте, вы можете запустить nosetests с опцией --with-doctest, чтобы включить плагин doctest.

нос также имеет интеграцию с coverage

nosetests --with-coverage.

Вы также можете использовать опции -cover-html --cover-html-dir для создания отчета по охвату HTML для каждого модуля, причем каждая строка кода, которая не тестируется, не указана. Я бы не стал слишком одержим получением покрытия, чтобы сообщить о 100% -ном охвате тестирования для всех модулей. Некоторый код лучше оставить для интеграционных тестов, которые я расскажу в конце.

Я стал огромным поклонником мини-диска, так как он очень упрощает тестирование кода с множеством внешних зависимостей. Хотя он работает очень хорошо, когда он сопряжен с doctest, его можно использовать с любой средой тестирования, используя класс unittest.TraceTracker. Я бы посоветовал вам не использовать его для тестирования всего вашего кода, поскольку вы все равно должны попытаться написать свой код, чтобы каждая единица перевода могла быть протестирована изолированно без издевательств. Иногда это невозможно.

Вот пример (непроверенный) такого теста с использованием minimock и unittest:

# tests/test_foo.py
import minimock
import unittest

import foo

class FooTest(unittest2.TestCase):
    def setUp(self):
        # Track all calls into our mock objects. If we don't use a TraceTracker
        # then all output will go to stdout, but we want to capture it.
        self.tracker = minimock.TraceTracker()

    def tearDown(self):
        # Restore all objects in global module state that minimock had
        # replaced.
        minimock.restore()

    def test_bar(self):
        # foo.bar invokes urllib2.urlopen, and then calls read() on the
        # resultin file object, so we'll use minimock to create a mocked
        # urllib2.
        urlopen_result = minimock.Mock('urlobject', tracker=self.tracker)
        urlopen_result.read = minimock.Mock(
            'urlobj.read', tracker=self.tracker, returns='OMG')
        foo.urllib2.urlopen = minimock.Mock(
            'urllib2.urlopen', tracker=self.tracker, returns=urlopen_result)

        # Now when we call foo.bar(URL) and it invokes
        # *urllib2.urlopen(URL).read()*, it will not actually send a request
        # to URL, but will instead give us back the dummy response body 'OMG',
        # which it then returns.
        self.assertEquals(foo.bar('http://example.com/foo'), 'OMG')

        # Now we can get trace info from minimock to verify that our mocked
        # urllib2 was used as intended. self.tracker has traced our calls to
        # *urllib2.urlopen()*
        minimock.assert_same_trace(self.tracker, """\
Called urllib2.urlopen('http://example.com/foo)
Called urlobj.read()
Called urlobj.close()""")

Единичные тесты не должны быть единственным типом тестов, которые вы пишете. Они, безусловно, полезны, и IMO чрезвычайно важно, если вы планируете поддерживать этот код в течение длительного периода времени. Они упрощают рефакторинг и помогают улавливать регрессии, но они действительно не проверяют взаимодействие между различными компонентами и как они взаимодействуют (если вы делаете это правильно).

Когда я начинаю доходить до того, что у меня есть готовый продукт с приличным покрытием для тестирования, который я намереваюсь выпустить, мне нравится писать хотя бы один интеграционный тест, который запускает полную программу в изолированной среде.

У меня был большой успех с этим в моем текущем проекте. У меня было около 80% покрытия unit test, а остальная часть кода была такой же, как разбор аргументов, диспетчеризация команд и состояние приложения верхнего уровня, что трудно охватить в модульных тестах. Эта программа имеет множество внешних зависимостей, поражая около десятка различных веб-сервисов и взаимодействуя с примерно 6 000 машин в производстве, поэтому выполнение этого по отдельности оказалось трудным.

В конце концов я написал интеграционный тест, который запускает сервер WSGI, написанный с eventlet и webob, который имитирует все сервисы, с которыми взаимодействует моя программа в процессе производства. Затем обезьяна интеграции тестирует нашу клиентскую библиотеку веб-сервисов, чтобы перехватить все HTTP-запросы и отправить их в приложение WSGI. После этого он загружает файл состояния, содержащий сериализованный снимок состояния кластера, и вызывает приложение, вызывая его функцию main(). Теперь все внешние службы, с которыми взаимодействует моя программа, моделируются, поэтому я могу запускать свою программу, так как она будет запускаться в процессе воспроизведения повторяющимся образом.

Ответ 5

Важно помнить о том, что тесты основаны на сравнении строк, а способ отображения чисел в виде строк будет различаться на разных платформах и даже в разных интерпретаторах python.

Большая часть моей работы посвящена вычислениям, поэтому я использую доктрины только для проверки своих примеров и моей версии. Я поместил несколько в __init__.py, так как это будет отображаться как первая страница моей документации, созданной с помощью epydoc.

Я использую нос для тестирования, хотя мне очень интересно проверить последние изменения на py.test.