Фикстуры Pytest
Фикстуры pytest - это функции, которые помогают создавать модульные, масштабируемые и поддерживаемые тесты. Вы используете средства для настройки предварительных условий для тестов, таких как подключения к базе данных, создание тестовых данных или настройка состояния системы, необходимого перед запуском теста. Их также можно использовать для очистки после завершения выполнения тестов.
Ключевыми характеристиками фикстур pytest являются следующие:
-
Контроль области: Светильники можно настроить для разных областей с помощью параметра
scope(напримерfunction,class,moduleилиsession), которые определяют, как часто вызывается светильник. - Обработка установки и сброса: Pytest управляет жизненным циклом фикстур, автоматически выполняет настройку и очистку по мере надобности.
- Внедрение зависимостей: фикстуры внедряются в тестовые функции в качестве аргументов, что делает понятно, какие тесты полагаются на какие фикстуры.
- Повторное использование и модульность: средства можно определить в одном месте и использовать в нескольких тестовых функциях, модулях или даже проектах.
Создание временного файл-фикстуры
При написании тестов, взаимодействующих с файлами, часто требуются временные файлы, которые не загромождают файловую систему после тестирования. С помощью pytest мы можем создать средство, которое настраивает временный файл. Этот модуль использует модуль Python tempfile для безопасного создания временных файлов, гарантируя, что они могут использоваться и удаляться без влияния на локальную среду. (В этой начальной версии нашей фикстуры файл не будет автоматически удален из-за флага delete=False. Мы будем обсуждать удаление файлов позже.)
Вот как выглядит светильник:
import pytest
import tempfile
@pytest.fixture
def tmp_file():
def create():
# Create a named temporary file that persists beyond the function scope
temp = tempfile.NamedTemporaryFile(delete=False)
return temp.name
return create
В этой конфигурации tmp_file() выступает в качестве крепежа. Имя светильника — это то, как тесты ссылались на него. В рамках фикстуры вложенная функция create() создает файл только при вызове, а не при настройке фикстуры. Это позволяет точно контролировать время создания временного файла, который полезен в тестах, где время и состояние файла критически важны.
Во вложенной функции create()создается временный файл, а затем возвращается абсолютный путь к нему. Ниже приведен пример того, как тест может использовать прибор, который мы написали:
import os
def test_file(tmp_file):
path = tmp_file()
assert os.path.exists(path)
Тест использует светильник, указав имя светильника в качестве аргумента. Наш простой вариант использования можно легко расширить, записав данные в файл или изменив такие параметры, как разрешения или права собственности.
Управление объёмом работ
В pytest управление жизненным циклом тестовых ресурсов с помощью процедур установки и удаления крайне важно для поддержания чистых и эффективных тестовых сред. Вы также хотите защитить целостность тестов, гарантируя, что каждый тест начинается с известного, согласованного состояния. По умолчанию средства pytest работают с областью function, которая влияет на поведение двумя способами:
- Жизненный цикл для каждого теста: возвращаемое значение светильника пересчитывается для каждой тестовой функции, которая использует ее, обеспечивая, чтобы каждый тест работал с свежим состоянием.
- Очистка после каждого использования: все необходимые операции очистки выполняются после каждого теста, используюющего средство.
Pytest также позволяет расширять области применения фикстур, чтобы оптимизировать производительность и использование ресурсов. Определение области особенно полезно в таких ситуациях, как управление состоянием базы данных или при наличии сложных настроек состояния, которые требует много времени для установки. Доступны четыре области:
-
function. По умолчанию, фиксатор выполняется однократно для каждого теста. -
class: Фикстура выполняется один раз на каждый тестовый класс. -
module: выполняется один раз для модуля. -
session: выполняется один раз за тестовую сессию. Эта область полезна для дорогостоящих операций, которые должны сохраняться на протяжении всего тестового сеанса, например инициализации службы или запуска сервера базы данных.
В этом случае выполнение однократно означает, что возвращаемое значение кэшируется. Таким образом, fixture с областью действия "module" может вызываться несколько раз в тестовом модуле, но возвращаемое значение будет таким же, как в первом тесте, который его вызвал.
Вот как будет выглядеть светильник tmp_file() в контексте модуля:
import pytest
import tempfile
@pytest.fixture(scope="module")
def tmp_file():
def create():
temp = tempfile.NamedTemporaryFile(delete=False)
return temp.name
return create
Управление очисткой
Предыдущий код, указывающий средство tmp_file, создает временный файл, но он не обрабатывает очистку автоматически после завершения тестов. Чтобы убедиться, что временные файлы не остаются позади, можно использовать request средства pytest для регистрации функции очистки.
Вот как изменить светильник tmp_file, чтобы добавить функцию автоматической очистки:
import pytest
import tempfile
import os
@pytest.fixture(scope="module")
def tmp_file(request):
# Create a temporary file that persists beyond the function scope
temp = tempfile.NamedTemporaryFile(delete=False)
def create():
# Returns the path of the temporary file
return temp.name
def cleanup():
# Remove the file after the tests are done
os.remove(temp.name)
# Register the cleanup function to be called after the last test in the module
request.addfinalizer(cleanup)
return create
При использовании request.addfinalizer() и передаче вложенной функции cleanup(), очистка вызывается в зависимости от области видимости. В этом случае область module, поэтому после всех тестов в модуле pytest вызывает эту функцию очистки.
Использование conftest.py
Вместо включения фикстур в тестовые файлы, их можно сохранить в файле conftest.py. Все исправления в conftest.py автоматически доступны для тестов в одном каталоге без необходимости явно импортировать их.
Изучение встроенных светильников
Pytest имеет множество встроенных светильников, предназначенных для упрощения тестирования. Эти средства позволяют автоматически обрабатывать настройку и очистку, позволяя сосредоточиться на написании тестовых случаев вместо управления тестами.
К встроенным светильникам относятся следующие:
-
cache. Используется для создания и управления кэшем уровня теста, который полезен для хранения данных между тестовыми сессиями. -
capsys: фиксирует и позволяет проверятьstderrиstdout, что упрощает проверку и тестирование выходных данных консоли. -
tmpdir. Предоставляет временный каталог для файлов, которые необходимо создать и использовать во время тестов. -
monkeypatch. Обеспечивает безопасный способ изменения поведения и значений объектов, функций и вашей среды ОС.
Роль monkeypatching в тестировании
Тестирование кода, тесно интегрируемого с внешними ресурсами, такими как базы данных или внешние API, может быть сложной из-за зависимостей, связанных с ними. Метод, называемый monkey patching, предполагает временное изменение вашей системы во время тестовых запусков, что обеспечивает независимость от внешних систем и позволяет безопасно изменять состояние и поведение вашей операционной среды во время тестирования.
Ниже приведен пример того, как переопределить функцию os.path.exists() с помощью приспособления monkeypatch:
import os
def test_os(monkeypatch):
# Override os.path.exists to always return False
monkeypatch.setattr('os.path.exists', lambda x: False)
assert not os.path.exists('/')
Кроме того, можно использовать метод setattr() с прямой ссылкой на объект и атрибут:
def test_os(monkeypatch):
# Specify the object and attribute to override
monkeypatch.setattr(os.path, 'exists', lambda x: False)
assert not os.path.exists('/')
Помимо задания атрибутов и переопределения методов, фикстура monkeypatch может задавать и удалять переменные среды, изменять значения словаря и модифицировать системные пути. Устройство monkeypatch автоматически отменяет все изменения после каждого теста, но при использовании устройства monkeypatch нужно проявлять осторожность. Вот некоторые причины, по которым следует быть внимательными при использовании:
-
Ясность кода и обслуживание: чрезмерное использование monkeypatch или использование его сложными способами может сделать тест более сложным для понимания и обслуживания. При чтении результатов теста может быть не сразу ясно, как компоненты должны вести себя нормально и как они изменяются для тестирования.
-
Проверка обоснованности: Обезьянопатчинг иногда может приводить к тестам, которые проходят в искусственных условиях, значительно отличающихся от производственной среды. Это может создать ложное чувство безопасности, поскольку тесты могут пройти из-за того, что тест чрезмерно изменил поведение системы.
-
Чрезмерная зависимость от деталей реализации: тесты, основанные на монкейпатчинге, могут быть сильно связаны с конкретными деталями реализации кода, который они тестируют. Это может сделать тесты хрупкими и уязвимыми к нарушению даже незначительных изменений в базовой базе кода.
-
Сложность отладки. Отладка тестов, которые используются monkeypatch , может быть более сложной, особенно если исправление изменяет фундаментальные аспекты поведения приложений. Понимание того, почему тест завершается сбоем, может потребовать более глубокого понимания того, как компоненты изменяются во время теста.
Хотя monkeypatch — это мощный инструмент для создания изолированных и контролируемых тестовых сред, он должен использоваться разумно и с четким пониманием того, как он влияет на набор тестов и поведение приложения.