Кеннет Рейтц – Автостопом по Python (страница 19)
class MySecondTest(unittest.TestCase):
····def test_that_fun_fails_when_not_adding_number(self):
········self.assertRaises(TypeError, fun, "multiply six by nine")
Методы теста должны начинаться со строки test — иначе они не запустятся. Тестовые модули должны следовать шаблону test*.py по умолчанию, но могут соответствовать любому шаблону, который вы передадите с помощью аргумента с ключевым словом pattern в командной строке.
Для того чтобы запустить все тесты в TestClass, откройте терминальную оболочку. Находясь в том же каталоге, где файл, вызовите из командной строки модуль unittest:
$ python — m unittest test_example.MyTest
.
---
Ran 1 test in 0.000s
OK
Для запуска всех тестов из файла укажите файл:
$ python — m unittest test_example
.
---
Ran 2 tests in 0.000s
OK
В версии Python 3.3 unittest.mock (https://docs.python.org/dev/library/unittest.mock) доступен в стандартной библиотеке. Он позволяет заменять тестируемые части системы mock-объектами и делать предположения о том, как они используются.
Например, вы можете написать
from unittest.mock import MagicMock
instance = ProductionClass()
instance.method = MagicMock(return_value=3)
instance.method(3, 4, 5, key='value')
instance.method.assert_called_with(3, 4, 5, key='value')
Для того чтобы создавать mock-классы и объекты при тестировании, используйте декоратор patch. В следующем примере поиск во внешней системе заменяется mock-объектом, который всегда возвращает одинаковый результат (патч существует только во время работы теста):
import unittest.mock as mock
def mock_search(self):
····class MockSearchQuerySet(SearchQuerySet):
········def __iter__(self):
············return iter(["foo", "bar", "baz"])
····return MockSearchQuerySet()
# SearchForm относится к ссылке на импортированный класс
# myapp.SearchForm и модифицирует этот объект, но не код,
# где определяется сам класс SearchForm
@mock.patch('myapp.SearchForm.search', mock_search)
def test_new_watchlist_activities(self):
····# get_search_results выполняет поиск и итерирует по результату
····self.assertEqual(len(myapp.get_search_results(q="fish")), 3)
Вы можете сконфигурировать модуль mock и управлять его поведением разными способами. Они подробно описаны в документации к unittest.mock.
Модуль doctest выполняет поиск фрагментов текста, которые похожи на интерактивные сессии Python в строках документации, а затем выполняет эти сессии, чтобы убедиться, что они работают именно так, как было показано.
Модуль doctest служит другой цели, нежели юнит-тесты. Они обычно менее детальны и не отлавливают особые случаи или регрессионные ошибки. Вместо этого они выступают в качестве содержательной документации основных вариантов использования модуля и его компонентов (в качестве примера можно рассмотреть сценарий «счастливый путь» (happy path — https://en.wikipedia.org/wiki/Happy_path)). Однако такие тесты должны запускаться автоматически каждый раз, когда запускается весь набор тестов.
Рассмотрим простой пример doctest:
def square(x):
····"""Squares x.
····>>> square(2)
····4
····>>> square(-2)
····4
····"""
····return x * x if __name__ == '__main__':
····import doctest
····doctest.testmod()
Когда вы запускаете этот модуль из командной строки (например, с помощью команды python module.py), такие тесты начнут выполняться и «пожалуются», если какой-то компонент ведет себя не так, как описано в строках документации.
Примеры
В этом разделе мы рассмотрим фрагменты наших любимых пакетов для того, чтобы подчеркнуть правила хорошего тона при тестировании реального кода. Набор тестов предполагает наличие дополнительных библиотек, не включенных в эти пакеты (например, для Requests требуется Flask, чтобы создать mock-сервер HTTP), которые включены в файлы requirements.txt их проектов.
Для всех этих примеров ожидаемым первым шагом будет открытие терминальной оболочки, изменение каталогов таким образом, чтобы они указывали на то место, где лежат исходники к вашим проектам, а также клонирование репозитория исходного кода и настройка виртуальной среды. Например, так:
$ git clone https://github.com/username/projectname.git
$ cd projectname
$ virtualenv — p python3 venv
$ source venv/bin/activate
(venv)$ pip install — r requirements.txt
Tablib использует модуль unittest стандартной библиотеки Python. Набор тестов не поставляется с пакетом. Для получения файлов вы должны клонировать репозиторий GitHub. Приводим основные моменты, выделив главные части.