test fixture что это
Python Testing с pytest. ГЛАВА 3 pytest Fixtures
Вернуться Дальше
Эта книга — недостающая глава, отсутствующая в каждой всеобъемлющей книге Python.
Frank Ruiz
Principal Site Reliability Engineer, Box, Inc.
Примеры в этой книге написаны с использованием Python 3.6 и pytest 3.2. pytest 3.2 поддерживает Python 2.6, 2.7 и Python 3.3+
Исходный код для проекта Tasks, а также для всех тестов, показанных в этой книге, доступен по ссылке на веб-странице книги в pragprog.com. Вам не нужно загружать исходный код, чтобы понять тестовый код; тестовый код представлен в удобной форме в примерах. Но что бы следовать вместе с задачами проекта, или адаптировать примеры тестирования для проверки своего собственного проекта (руки у вас развязаны!), вы должны перейти на веб-страницу книги и скачать работу. Там же, на веб-странице книги есть ссылка для сообщений errata и дискуссионный форум.
Под спойлером приведен список статей этой серии.
Теперь, когда вы познакомились с основами pytest, поглядим повнимательнее на фикстуры, которые необходимы для структурирования тестового кода практически для любой нетривиальной программной системы. Fixtures — это функции, выполняемые pytest до (а иногда и после) фактических тестовых функций. Код в фикстуре может делать все, что вам необходимо. Вы можете использовать Fixtures, чтобы получить набор данных для тестирования. Вы можете использовать Fixtures, чтобы получить систему в известном состоянии перед запуском теста. Fixtures также используются для получения данных для нескольких тестов.
Вот простой пример фикстуры, который возвращает число:
Декоратор @pytest.fixture() используется, чтобы сообщить pytest, что функция является фикстурой. Когда вы включаете имя фикстуры в список параметров тестовой функции, pytest знает, как запустить её перед запуском теста. Фикстуры могут выполнять работу, а могут возвращать данные в тестовую функцию.
Независимо от других смысловых значений, в pytest и в этой книге test fixtures относятся к механизму, который обеспечивает pytest, чтобы отделить код “подготовка к (getting ready for)” и “очистка после (cleaning up after)” от ваших тестовых функций.
pytest fixtures — одна из уникальных фишек, которые поднимают pytest над другими тестовыми средами, и являются причиной того, почему многие уважаемые люди переключаются на… и остаются с pytest. Тем не менее, фикстуры в pytest отличаются от фикстур в Django и отличаются от процедур setup и teardown, обнаруженных в unittest и nose. Есть много особенностей и нюансов если говорить о фикстурах. Как только вы получите хорошую ментальную модель того, как они работают, вам станет полегче. Тем не менее, вам нужно поиграться с ними некоторое время, чтобы въехать, поэтому давайте начнем.
Обмен Fixtures через conftest.py
Использование Fixtures вместо Setup и Teardown
К счастью, pytest включает в себя отличную фикстуру под названием tmpdir. Мы можем использовать её для тестирования и не должны беспокоиться о очистке. Это не магия, просто хорошая практика кодирования от самых пытливых людей. (Не переживайте; мы разберем tmpdir и более подробно распишем его с помощью tmpdir_factory в разделе «Использование tmpdir и tmpdir_factory» на стр. 71.)
С учетом всех этих составляющих, эта фикстура работает замечательно:
ch3/a/ tasks_proj /tests/conftest.py
Функция fixture запускается перед тестами, которые ее используют. Однако, если в функции есть yield, то там произойдёт остановка, контроль передастся тестам и выполняется следующая за yield строка после завершения тестов. Поэтому подумайте о коде над yield как о «setup», а о коде после yield как о «teardown». Код после yield «teardown» будет выполняться независимо от того, что происходит во время тестов. Мы не возвращаем данные с выходом в этомй фикстуре. Но вы можете.
Основное изменение здесь заключается в том, что дополнительная фикстура в файле была удалена, и мы добавили tasks_db в список параметров теста. Мне нравится структурировать тесты в форматеGIVEN/WHEN/THEN (ДАНО/КОГДА/ПОСЛЕ), используя комментарии, особенно если это не очевидно из кода, что происходит. Я думаю, что это полезно в этом случае. Надеюсь, GIVEN инициализированные задачи db помогут выяснить, почему tasks_db используется в качестве инструмента для теста.
Убедитесь, что Tasks установлен
Трассировка Fixture Execution с –setup-show
Если вы запустите тест из последнего раздела, вы не увидите, какие фикстуры запущены:
F и S перед именами фикстур указывают область. F для области действия и S для области сеанса. Я расскажу о сфере действия в разделе «Спецификация областей(Scope) Fixture» на стр. 56.
Использование Fixtures для Test Data
Fixtures являются отличным местом хранения данных для тестирования. Вы можете вернуть всё что угодно. Вот фикстура, возвращающая кортеж смешанного типа:
Поскольку test_a_tuple() должен завершиться неудачей (23! = 32), мы увидим, что произойдет, когда тест с фикстурой потерпит неудачу:
Вместе с разделом трассировки стека pytest отображает параметры значения функции, вызвавшей исключение или не прошедшей assert. В случае проведения тестов фикстуры — это параметры для теста, поэтому о них сообщается с помощью трассировки стека. Что произойдет, если assert (или exception) случиться в fixture?
Происходит пара вещей. Трассировка стека правильно показывает, что assert произошёл в функции фикстуры. Кроме того, test_other_data сообщается не как FAIL, а как ERROR. Это серьёзное различие. Если тест вдруг терпит неудачу, вы знаете, что сбой произошел в самом тесте, а не зависит от какой то фикстуры.
Но как насчет проекта Tasks? Для проекта Tasks мы, вероятно, могли бы использовать некоторые фикстуры данных, возможно, различные списки задач с различными свойствами:
ch3/a/tasks_proj/tests/conftest.py
Вы можете использовать их непосредственно из тестов, или из других фикстур. Давайте создадим с их помощью непустые базы данных для тестирования.
Использование Multiple Fixtures
Вы уже видели, что tmpdir использует tmpdir_factory. И вы использовали tmpdir в нашем task_db fixture. Давайте продолжим цепочку и добавим некоторые специализированные фикстуры для непустых баз проекта tasks:
ch3/a/tasks_proj/tests/conftest.py
Все эти fixtures включают две фикстуры в свой список параметров: tasks_db и набор данных. Набор данных используется для добавления задач в базу данных. Теперь тесты могут использовать их, если вы хотите, чтобы тест начинался с непустой базы данных, например:
ch3/a/tasks_proj/tests/func/test_add.py
Это также демонстрирует одну из главных причин использования fixtures: чтобы сфокусировать тест на том, что вы на самом деле тестируете, а не на том, что вы должны были сделать, чтобы подготовиться к тесту. Мне нравится использовать комментарии для GIVEN/WHEN/THEN и пытаться протолкнуть как можно больше данных (GIVEN) в фикстуры по двум причинам. Во-первых, это делает тест более читаемым и, следовательно, более ремонтопригодным. Во-вторых, assert или exception в фикстуре приводит к ошибке (ERROR), в то время как assert или exception в тестовой функции приводит к ошибке (FAIL). Я не хочу, чтобы test_add_increases_count() отказал, если инициализация базы данных завершилась неудачно. Это просто сбивает с толку. Я хочу, чтобы сбой (FAIL) test_add_increases_count() был возможен только в том случае, если add () действительно не смог изменить счетчик. Давайте запустим и посмотрим, как работают все фикстуры:
Получили снова кучу F-ов и S для функции и области сеанса. Давайте разберем, что это.
Спецификация областей(Scope) Fixture
Фикстуры включают в себя необязательный параметр под названием scope, который определяет, как часто фикстура получает setup и teardown. Параметр scope для @pytest.fixture() может иметь значения функции, класса, модуля или сессии. Scope по умолчанию — это функция. Настройки tasks_db и все фикстуры пока не определяют область. Таким образом, они являются функциональными фикстурами.
Ниже приведено краткое описание каждого значения Scope:
Выполняется один раз для каждой функции теста. Часть setup запускается перед каждым тестом с помощью fixture. Часть teardown запускается после каждого теста с использованием fixture. Это область используемая по умолчанию, если параметр scope не указан.
Выполняется один раз для каждого тестового класса, независимо от количества тестовых методов в классе.
Выполняется один раз для каждого модуля, независимо от того, сколько тестовых функций или методов или других фикстур при использовании модуля.
Выполняется один раз за сеанс. Все методы и функции тестирования, использующие фикстуру области сеанса, используют один вызов setup и teardown.
Вот как выглядят значения scope в действии:
Теперь вы можете видеть не только F и S для функции и сеанса, но также C и M для класса и модуля.
Область(scope) определяется с помощью фикстуры. Я знаю, что это очевидно из кода, но это важный момент, чтобы убедиться, что вы полностью грокаете (Прим переводчика: грокать — скорее всего автор имеет ввиду термин из романа Роберта Хайнлайна «Чужак в стране чужой». Приблизительное значение «глубоко и интуитивно понимать»). Область(scope) задается в определении фикстуры, а не в месте её вызова. Тестовые функции, которые используют фикстуру, не контролируют, как часто устанавливается(SETUP) и срывается(TEARDOWN) фикстура.
Фикстуры могут зависеть только от других фикстур из той же или более расширенной области(scope). Таким образом, function scope fixture может зависеть от других function scope fixture (по умолчанию и используется в проекте Tasks до сих пор). function scope fixture также может зависеть от класса, модуля и фикстур области сеанса, но в обратном порядке — никогда.
Смена Scope для Tasks Project Fixtures
С учетом этих знаний о scope, давайте теперь изменим область действия некоторых фикстур проекта Task.
До сих пор у нас не было проблем со временем тестирования. Но, согласитесь, что бесполезно создавать временный каталог и новое соединение с базой данных для каждого теста. Пока мы можем обеспечить пустую базу данных, когда это необходимо, этого должно быть достаточно.
ch3/b/tasks_proj/tests/conftest.py
Фикстуры данных просто возвращают значение, поэтому действительно нет причин, чтобы они работали все время. Один раз за сеанс достаточно:
ch3/b/tasks_proj/tests/conftest.py
Теперь давайте посмотрим, будут ли все эти изменения работать с нашими тестами:
Похоже, все в порядке. Давайте проследим фикстуры для одного тестового файла, чтобы увидеть, что различные области работают в соответствии с нашими ожиданиям:
Ага. Выглядит правильно. tasks_db_session вызывается один раз за сеанс, а более быстрый task_db теперь просто очищает базу данных перед каждым тестом.
Specifying Fixtures with usefixtures
Использование usefixtures почти то же самое, что указание имени фикстуры в списке параметров метода теста. Единственное отличие состоит в том, что тест может использовать возвращаемое значение фикстуры, только если оно указано в списке параметров. Тест, использующий фикстуру из-за использования usefixtures, не может использовать возвращаемое значение фикстуры.
Использование autouse для Fixtures That Always Get Used (которые используются непрерывно)
До сих пор в этой главе все фикстуры, используемые тестами, были обертками тестов (или использовали usefixtures для этого одного примера класса). Однако вы можете использовать autouse=True, чтобы фикстура работала постоянно. Это хорошо работает для кода, который вы хотите запустить в определенное время, но тесты на самом деле не зависят от состояния системы или данных из фикстуры. Вот довольно надуманный пример:
Тут мы демонстрируем добавление время тестирования после каждого теста, а также дату и текущее время в конце сеанса. Вот как всё это выглядит:
Функция autouse хорошо сработала. Но это скорее исключение, чем правило. Используйте фикстуры как декораторы, если у вас нет действительно большой причины не делать этого.
Теперь, когда вы видели autouse в действии, возможно вас интересует, почему мы не использовали его для tasks_db в этой главе. В проекте Tasks я чувствовал, что важно сохранить возможность проверить, что произойдет, если мы попытаемся использовать функцию API до инициализации БД. Это должно привести к соответствующему исключению. Но мы не сможем это проверить, если принудительно инициализировать каждый тест.
Переименование Fixtures
Название фикстур, перечисленные в списке параметров тестов и других фикстур, использующих их, обычно совпадает с именем функции фикстуры. Однако, pytest позволяет вам переименовывать фикстуры с параметром name в @pytest.fixture() :
ch3/ test_rename_fixture.py
Большая часть вывода не показана — там много чего. К счастью, фикстуры, которые мы определили, находятся внизу, вместе с тем, где они определены. Мы можем использовать это, чтобы найти определение lue. Давайте используем это в проекте «Tasks»:
Параметризация Фикстур
В [Parametrized Testing]Параметризованном тестировании, на стр. 42, мы параметризовали тесты. Мы также можем параметризовать фикстуры. Мы по-прежнему используем наш список задач, список идентификаторов задач и функцию эквивалентности, как и раньше:
Но теперь, вместо параметризации теста, мы параметризуем фикстуру под названием a_task :
ch3/b/tasks_proj/tests/func/ test_add_variety2.py
Элемент a_task довольно прост — он просто возвращает request.param в качестве значения для теста, используя его. Поскольку наш список задач состоит из четырех задач, фикстура будет вызываться четыре раза, а затем тест будет вызываться четыре раза:
Мы не предоставили идентификаторы, так pytest сам выдумал имена, добавив номер вызова(число) к имени фикстуры. Однако мы можем использовать тот же список строк, который мы использовали при параметризации наших тестов:
ch3/b/tasks_proj/tests/func/ test_add_variety2.py
Этот вариант дает нам идентификаторы получше:
Мы также можем установить параметр ids в функцию, которую мы пишем, которая предоставляет идентификаторы. Вот как это выглядит, когда мы используем функцию для генерации идентификаторов:
ch3/b/tasks_proj/tests/func/ test_add_variety2.py
Функция будет вызвана из значения каждого элемента из параметризации. Поскольку параметризация представляет собой список объектов Task, id_func() будет вызываться с объектом Task, что позволяет нам использовать методы доступа namedtuple для доступа к одному объекту Task для генерации идентификатора одного объекта Task за раз. Это немного чище, чем генерировать полный список раньше времени, и выглядит одинаково:
С параметризованными функциями вы можете запускать эту функцию несколько раз. Но с параметризованными фикстурами каждая тестовая функция, использующая эту фикстуру, будет вызываться несколько раз. И в этом сила, брат!
Параметризация Fixtures в Tasks Project
Теперь давайте посмотрим, как мы можем использовать параметризованные фикстуры в проекте Tasks. До сих пор мы использовали TinyDB для всех тестов. Но мы хотим, чтобы наши варианты оставались открытыми до конца проекта. Поэтому любой код, который мы пишем, и любые тесты, которые мы пишем, должны работать как с TinyDB, так и с MongoDB.
Решение (в коде), для которого используется база данных, изолируется от вызова start_tasks_db() в фикстуре tasks_db_session :
Параметр db_type в вызове start_tasks_db() не является магическим. Он просто завершает переключение на подсистему, которая отвечает за остальные взаимодействия с базой данных:
Чтобы протестировать MongoDB, нам нужно запустить все тесты с db_type равным mongo. Небольшая хитрость:
Здесь я добавил params=[‘tiny’,’ mongo’] в фикстуру-декоратор. Ещё добавил request в список параметров temp_db и установил db_type в request.param вместо того, чтобы просто выбрать «tiny» или «mongo».
Installing MongoDB
Чтобы отслеживать тестирование MongoDB, убедитесь, что установлены MongoDB и pymongo. Лично я тестировал с изданием сообщества MongoDB, найденным тут https://www.mongodb.com/download-center. pymongo установливается с pip—pip install pymongo. Однако использование MongoDB не обязательно поддерживать всю остальную часть книги; он используется в этом примере и в примере отладчика в Главе 7.
Вот что мы пока имеем:
Хм. Облом. Похоже, нам нужно будет изрядно отладиться, прежде чем мы позволим кому-либо использовать версию Mongo. Вы узнаете, как отладить это в pdb: Отладка тестовых сбоев, на стр. 125. До тех пор мы будем использовать версию TinyDB.
Упражнения
Что дальше
Реализация pytest fixture достаточно гибкая, чтобы использовать фикстуры, такие как building blocks, для создания тестового setup и teardown, а также для смены различных фрагментов системы (например, замена Mongo для TinyDB). Поскольку фикстуры настолько гибкие, я использую их в значительной степени, чтобы как можно больше настроить мои тесты на фикстуры.
В этой главе вы рассмотрели фикстуры pytest, которые пишете сами, а также пару встроенных(builtin) фикстур tmpdir и tmpdir_factory. В следующей главе вы подробно рассмотрите встроенные (builtin) фикстуры.
Вернуться Дальше
Python Testing с pytest. Builtin Fixtures, Глава 4
Вернуться Дальше
Встроенные фикстуры, которые поставляются с pytest, могут помочь вам сделать довольно полезные вещи в ваших тестах легко и непринужденно. Например, помимо обработки временных файлов, pytest включает встроенные фикстуры для доступа к параметрам командной строки, связи между сеансами тестирования, проверки выходных потоков, изменения переменных среды и опроса предупреждений.
Исходный код для проекта Tasks, а также для всех тестов, показанных в этой книге, доступен по ссылке на веб-странице книги в pragprog.com. Вам не нужно загружать исходный код, чтобы понять тестовый код; тестовый код представлен в удобной форме в примерах. Но что бы следовать вместе с задачами проекта, или адаптировать примеры тестирования, чтобы проверить свой собственный проект (руки у вас развязаны!), вы должны перейти на веб-страницу книги, чтобы скачать работу. Там же, на веб-странице книги есть ссылка на сообщение errata и дискуссионный форум.
Под спойлером приведен список статей этой серии.
В предыдущей главе вы рассмотрели, что такое фикстуры, как их писать и как их использовать для тестовых данных, а также для setup и teardown кода.
Повторное использование обычных фикстур настолько хорошая идея, что разработчики pytest включили некоторые часто требующиеся фикстуры в pytest. Вы уже видели, как tmpdir и tmpdir_factory используются проектом Tasks в разделе смены области для фикстур проекта Tasks на странице 59. Вы разберете их более подробно в этой главе.
Встроенные фикстуры, которые поставляются с pytest, могут помочь вам сделать довольно полезные вещи в ваших тестах легко и непринужденно. Например, помимо обработки временных файлов, pytest включает встроенные фикстуры для доступа к параметрам командной строки, связи между сеансами тестирования, проверки выходных потоков, изменения переменных среды и опроса предупреждений. Встроенные фикстуры — это расширения функциональности ядра pytest. Давайте теперь посмотрим на несколько из наиболее часто используемых встроенных фикстур по порядку.
Использование tmpdir и tmpdir_factory
Вот простой пример использования tmpdir :
Во второй строке примера tmpdir_factory функция getbasetemp() возвращает базовый каталог, используемый для данного сеанса. Оператор print в примере нужен, чтобы можно было посмотреть каталог в вашей системе. Давайте посмотрим, где он находится:
Использование временных каталогов для других областей
Например, предположим, что у нас есть модуль, полный тестов, и многие из них должны иметь возможность читать некоторые данные из файла json. Мы смогли положить фикстуру объема модуля в сам модуль, или в conftest.py файл, который настраивает файл данных следующим образом:
Фикстура author_file_json() создает временный каталог с именем data и создает файл с именем author_file.json в каталоге данных. Затем записывает словарь python_author_data как json. Поскольку это фикстура области модуля, json-файл будет создан только один раз для каждого модуля, использующего тест:
ch4/authors/test_authors.py
Оба теста будут использовать один и тот же JSON-файл. Если один файл тестовых данных работает для нескольких тестов, нет смысла создавать его заново для обоих тестов.
Использование pytestconfig
С помощью встроенной фикстуры pytestconfig вы можете управлять тем, как pytest работает с аргументами и параметрами командной строки, файлами конфигурации, плагинами и каталогом, из которого вы запустили pytest. Фикстура pytestconfig является ярлыком для request.config, и иногда упоминается в документации pytest как «the pytest config object«(объект конфигурации pytest).
Чтобы узнать, как работает pytestconfig, вы можете посмотреть, как добавить пользовательский параметр командной строки и прочитать значение параметра из теста. Прочитать значение параметров командной строки вы сможете непосредственно из pytestconfig, но чтобы добавить параметр и проанализировать его, вам нужно добавить функцию-ловушку (hook). Функции hook, которые я более подробно описываю в Главе 5, «Плагины», на стр. 95, являются еще одним способом управления поведением pytest и часто используются в плагинах. Однако добавление пользовательской опции командной строки и чтение ее из pytestconfig достаточно широко распространено, поэтому я хочу осветить это здесь.
Добавление параметров командной строки через pytest_addoption должно выполняться через плагины или в файле conftest.py расположенного в верхней части структуры каталога проекта. Вы не должны делать это в тестовом подкаталоге.
Теперь мы можем получить доступ к этим опциям из теста:
Давайте посмотрим, как это работает:
Поскольку pytestconfig является фикстурой, его также можно получить из других фикстур. Вы можете сделать фикстуры для имен опций, если хотите, например:
Вы также можете получить доступ к встроенным параметрам, а не только к добавляемым, а также к информации о том, как был запущен pytest (каталог, аргументы и т.д.).
Вот пример нескольких значений и параметров конфигурации:
Мы вернемся к pytestconfig, когда я продемонстрирую ini-файлы в главе 6 «Конфигурация» на стр. 113.
Using cache
Обычно мы, тестировщики, думаем, что каждый тест максимально независим от других тестов. Следует убедиться, что не закрались зависимости учёта порядка. Хотелось бы иметь возможность запустить или перезапустить любой тест в любом порядке и получить тот же результат. Кроме того, надо, чтобы сеансы тестирования были повторяемыми и не изменяли поведение на основе предыдущих сеансов тестирования.
Чтобы увидеть их в действии, будем использовать эти два теста:
Вот параметризованный тест с одним сбоем:
Может быть, вы можете определить проблему сразу. Но давайте представим, что тест длиннее и сложнее, и не так уж очевидно, что тут не так. Давайте снова запустим тест, чтобы снова увидеть ошибку. Тестовый случай можно указать в командной строке:
Причина неудачи должна быть более очевидной.
Или вы можете посмотреть в директории кэша:
Интерфейс для кеш-фикстуры простой.
Вот наша фикстура, используемая для фиксации времени тестов:
Поскольку фикстура является autouse, на неё не нужно ссылаться из теста. Объект request используется для получения nodeid что бы использовать в ключе. nodeid — уникальный идентификатор, который работает даже с параметризованными тестами. Мы добавляем ключ с ‘duration/’, чтобы быть добропорядочныи жителями кэша. Код выше yield выполняется до тестовой функции; код после yield выполняется после тестовой функции.
Теперь нам нужны некоторые тесты, которые занимают разные промежутки времени:
Поскольку вы, вероятно, не хотите писать кучу тестов для этого, я использовал random и параметризацию, чтобы легко cгенерить некоторые тесты, которые поспят в течение случайного количества времени, все короче секунды. Давайте посмотрим пару раз, как это работает:
Что ж, это было весело. Давайте посмотрим, что в кэше:
Вы можете легко увидеть данные duration (продолжительности) отдельно от данных кэша из-за префикса имен данных кэша. Тем не менее, интересно, что функциональность lastfailed может работать с одной записью кэша. Наши данные о продолжительности занимают одну запись в кэше для каждого теста. Давайте последуем примеру lastfailed и поместим наши данные в одну запись.
Вот одна из возможных реорганизаций одной и той же функциональности:
После запуска его пару раз, давайте посмотрим на сохраненный кэш:
Использование capsys
Фикстура capsys builtin обеспечивает две функциональные возможности: позволяет получить stdout и stderr из некоторого кода, и временно отключить захват вывода. Давайте посмотрим на получение stdout и stderr.
Предположим, у вас есть функция для печати приветствия для stdout:
Вы не можете проверить это, проверив возвращаемое значение. Вы должны как-то проверить stdout. Вы можете проверить результат с помощью capsys:
Теперь, ‘always print this’ всегда будет выводиться:
Использование monkeypatch
«monkey patch» — это динамическая модификация класса или модуля во время выполнения. Во время тестирования «monkey patching» — это удобный способ взять на себя часть среды выполнения тестируемого кода и заменить либо входные зависимости, либо выходные зависимости объектами или функциями, которые более удобны для тестирования. Встроенная фикстура monkeypatch позволяет сделать это в контексте одного теста. И когда тест заканчивается, независимо от того, пройден он или нет, оригинал восстанавливается, отменяя все изменения патча. Все это очень запутано, пока мы не перейдем к некоторым примерам. После изучения API мы рассмотрим, как monkeypatch используется в тестовом коде.
Фикстура monkeypatch обеспечивает следующие функции:
Параметр raising указывает pytest, следует ли создавать исключение, если элемент еще не существует. Параметр prepend для setenv() может быть символом. Если он установлен, значение переменной среды будет изменено на значение + prepend +
- .
Чтобы увидеть monkeypatch в действии, давайте посмотрим на код, который пишет dot-файл конфигурации. Поведение некоторых программ может быть изменено с помощью настроек и значений, заданных в dot-файле в домашнем каталоге пользователя. Вот несколько строк кода, который читает и записывает cheese-файл персональных настроек:
Одна из проблем с этим заключается в том, что любой, кто запустит этот тестовый код, перезапишет свой собственный cheese-файл настроек. В этом нет ничего хорошего.
Во время теста все, что в модуле cheese вызывает os.path.expanduser() получает вместо этого наше лямбда-выражение. Эта небольшая функция использует функцию модуля регулярного выражения re.sub для замены
Предположим, мы обеспокоены тем, что произойдет, если файл уже существует. Мы хотим быть уверенным, что он будет перезаписан по умолчанию, когда вызывается write_default_cheese_preferences() :
Использование doctest_namespace
Один из способов исправить это-поместить инструкцию import в каждую docstring:
Это определенно устраняет проблему:
Однако он также загромождает docstrings и не добавляет никакой реальной ценности читателям кода.
Я расскажу о запуске doctest из pytest в главе 7 «Использование pytest с другими инструментами» на стр. 125.
Использование recwarn
Встроенная фикстура recwarn используется для проверки предупреждений, генерируемых тестируемым кодом. В Python вы можете добавлять предупреждения, которые очень похожи на утверждения, но используются для случаев, при которых не нужно останавливать выполнение. Например, предположим, что мы хотим прекратить поддерживать функцию, которую нам хотелось бы никогда не добавлять в пакет, но пришлось включить для других пользователей. Мы можем поместить предупреждение в код и оставить его там для пары выпусков:
Мы можем убедиться, что предупреждение выдается правильно с тестом:
Значение recwarn действует как список предупреждений, и каждое предупреждение в списке имеет определенную category (категорию), message (сообщение), filename (имя файла) и lineno (номер строки), как показано в коде.
Контекстный менеджер pytest.warns() предоставляет элегантный способ отделения части кода для проверки предупреждения. Элемент recwarn и диспетчер контекста pytest.warns() обеспечивают аналогичную функциональность, поэтому решение о том, что использовать, является исключительно вопросом вкуса.
Упражнения
Что дальше
В этой главе вы рассмотрели несколько встроенных фикстур pytest. Далее вы более подробно рассмотрите Плагины. Нюансы написания больших плагинов могут стать книгой сами по себе; однако небольшие пользовательские плагины являются регулярной частью экосистемы pytest.
Вернуться Дальше