
Методы теста должны начинаться со строки 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
Mock (в модуле unittest)
В версии Python 3.3 unittest.mock ( https://docs.python.org/dev/library/unittest.mock) доступен в стандартной библиотеке. Он позволяет заменять тестируемые части системы mock-объектами и делать предположения о том, как они используются.
Например, вы можете написать обезьяний патч для метода, похожий на тот, что показан в предыдущем примере (обезьяний патч — это код, который модифицирует или заменяет другой существующий код во время работы программы). В этом коде существующий метод с именем ProductionClass.method (в случае если мы создали именованный объект) заменяется новым объектом MagicMock, который при вызове всегда будет возвращать значение 3. Кроме того, этот объект считает количество получаемых вызовов, записывает сигнатуру, с помощью которой был вызван, и содержит методы с выражением, необходимые для тестов:
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
Модуль 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 их проектов.
Для всех этих примеров ожидаемым первым шагом будет открытие терминальной оболочки, изменение каталогов таким образом, чтобы они указывали на то место, где лежат исходники к вашим проектам, а также клонирование репозитория исходного кода и настройка виртуальной среды. Например, так:
Читать дальше