О светильниках

См.также

Fixtures reference

Фикстуры pytest разработаны таким образом, чтобы быть явными, модульными и масштабируемыми.

Какие приспособления являются

При тестировании fixture обеспечивает определенный, надежный и последовательный контекст для тестов. Это может быть среда (например, база данных, настроенная с известными параметрами) или содержимое (например, набор данных).

Фикстуры определяют шаги и данные, которые составляют фазу arrange теста (см. Анатомия теста). В pytest это определяемые вами функции, которые служат этой цели. Их также можно использовать для определения фазы act теста; это мощная техника для разработки более сложных тестов.

Доступ к сервисам, состояниям или другим операционным средам, заданным приспособлениями, тестовые функции получают через аргументы. Для каждого приспособления, используемого тестовой функцией, в определении тестовой функции обычно имеется параметр (названный по имени приспособления).

Мы можем сказать pytest, что определенная функция является фикстурой, украсив ее @pytest.fixture. Вот простой пример того, как может выглядеть фикстура в pytest:

import pytest


class Fruit:
    def __init__(self, name):
        self.name = name

    def __eq__(self, other):
        return self.name == other.name


@pytest.fixture
def my_fruit():
    return Fruit("apple")


@pytest.fixture
def fruit_basket(my_fruit):
    return [Fruit("banana"), my_fruit]


def test_my_fruit_in_basket(my_fruit, fruit_basket):
    assert my_fruit in fruit_basket

Тесты также не обязательно должны ограничиваться одним приспособлением. Они могут зависеть от любого количества фикстур, а фикстуры могут использовать другие фикстуры. Именно здесь система фикстур pytest действительно сияет.

Улучшения по сравнению с функциями установки/исчезновения в стиле xUnit

Фикстуры pytest предлагают значительные улучшения по сравнению с классическим стилем xUnit - функциями setup/teardown:

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

  • приспособления реализованы модульно, поскольку каждое имя приспособления вызывает функцию приспособления, которая сама может использовать другие приспособления.

  • Управление приспособлениями масштабируется от простого модульного до сложного функционального тестирования, позволяя параметризировать приспособления и тесты в соответствии с конфигурацией и параметрами компонентов, или повторно использовать приспособления в рамках функций, классов, модулей или всего сеанса тестирования.

  • Логика разрушения может легко и безопасно управляться независимо от количества используемых приспособлений, без необходимости тщательно обрабатывать ошибки вручную или микроконтролировать порядок добавления шагов очистки.

Кроме того, pytest продолжает поддерживать Как реализовать настройку в стиле xunit. Вы можете смешивать оба стиля, постепенно переходя от классического стиля к новому, как вам больше нравится. Вы также можете начать с существующих проектов unittest.TestCase style или nose based.

Ошибки крепления

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

Если тест помечен как имеющий ошибку, это не означает, что тест не прошел. Это означает, что тест даже не удалось выполнить, потому что возникла проблема с одной из вещей, от которых он зависит.

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

Вот небольшой пример, который поможет объяснить:

import pytest


@pytest.fixture
def order():
    return []


@pytest.fixture
def append_first(order):
    order.append(1)


@pytest.fixture
def append_second(order, append_first):
    order.extend([2])


@pytest.fixture(autouse=True)
def append_third(order, append_second):
    order += [3]


def test_order(order):
    assert order == [1, 2, 3]

Если по какой-то причине в order.append(1) возникнет ошибка и он вызовет исключение, мы не сможем узнать, будут ли проблемы у order.extend([2]) или order += [3]. После того, как append_first выдаст исключение, pytest больше не будет запускать никаких исправлений для test_order, и даже не будет пытаться запустить test_order самостоятельно. Единственные вещи, которые могли бы быть запущены, это order и append_first.

Совместное использование данных тестирования

Если вы хотите сделать тестовые данные из файлов доступными для ваших тестов, хороший способ сделать это - загрузить эти данные в фикстуру для использования вашими тестами. Это позволяет использовать механизмы автоматического кэширования pytest.

Другим хорошим подходом является добавление файлов данных в папку tests. Существуют также плагины сообщества, помогающие управлять этим аспектом тестирования, например pytest-datadir и pytest-datafiles.

Замечание об очистке приспособлений

pytest не делает никакой специальной обработки для сигналов SIGTERM и SIGQUIT (SIGINT обрабатывается естественно средой выполнения Python через KeyboardInterrupt), поэтому приспособления, управляющие внешними ресурсами, которые должны быть очищены при завершении процесса Python (по этим сигналам), могут утекать ресурсы.

Причина, по которой pytest не обрабатывает эти сигналы для выполнения очистки приспособления, заключается в том, что обработчики сигналов являются глобальными, и их изменение может вмешаться в выполняемый код.

Если фикстуры в вашем наборе требуют особого внимания к завершению в этих сценариях, смотрите this comment в трекере проблем для возможного обходного пути.

Вернуться на верх