pytest-2.3: обоснование эволюции фикстур/функаргов¶
Целевая аудитория: Чтение этого документа требует базовых знаний тестирования на python, методов настройки xUnit и (предыдущего) базового механизма pytest funcarg, см. фанкарги и pytest_funcarg__.. Если вы новичок в pytest, то можете просто проигнорировать этот раздел и прочитать другие разделы.
Недостатки предыдущего механизма pytest_funcarg__¶
До pytest-2.3 механизм funcarg вызывал фабрику каждый раз, когда требовался funcarg для тестовой функции.  Если фабрика хочет повторно использовать ресурс в разных диапазонах, она часто использует помощник request.cached_setup() для управления кэшированием ресурсов.  Вот базовый пример того, как мы можем реализовать объект базы данных для каждой сессии:
# content of conftest.py
class Database:
    def __init__(self):
        print("database instance created")
    def destroy(self):
        print("database instance destroyed")
def pytest_funcarg__db(request):
    return request.cached_setup(
        setup=DataBase, teardown=lambda db: db.destroy, scope="session"
    )
Этот подход имеет ряд ограничений и трудностей:
- Создание ресурсов funcarg не является простым, вместо этого необходимо разобраться в сложной механике метода cached_setup(). 
- Параметризация ресурса «db» не является простой задачей: необходимо применить декоратор «parametrize» или реализовать хук - pytest_generate_tests(), вызывающий- parametrize(), который выполняет параметризацию в местах использования ресурса. Более того, необходимо модифицировать фабрику, чтобы использовать параметр- extrakey, содержащий- request.paramдля вызова- Request.cached_setup.
- Несколько параметризованных ресурсов, скопированных на сессию, будут активны одновременно, что затрудняет их влияние на глобальное состояние тестируемого приложения. 
- вы никак не можете использовать фабрики funcarg в методах настройки xUnit. 
- Непараметризованная функция приспособления не может использовать параметризованный ресурс funcarg, если это не указано в сигнатуре тестовой функции. 
Все эти ограничения устранены в pytest-2.3 и его улучшенном fixture mechanism.
Прямое масштабирование фабрик приспособлений/функаргов¶
Вместо того чтобы вызывать cached_setup() с областью действия кэша, вы можете использовать декоратор @pytest.fixture и напрямую указать область действия:
@pytest.fixture(scope="session")
def db(request):
    # factory will only be invoked once per session -
    db = DataBase()
    request.addfinalizer(db.destroy)  # destroy when session is finished
    return db
Этой реализации фабрики больше не нужно вызывать cached_setup(), поскольку она будет вызываться только один раз за сессию.  Более того, request.addfinalizer() регистрирует финализатор в соответствии с указанной областью действия ресурса, над которым работает фабричная функция.
Прямая параметризация фабрик ресурсов funcarg¶
Ранее фабрики funcarg не могли напрямую вызывать параметризацию. Для выполнения параметризации, т.е. вызова теста несколько раз с разными наборами значений, необходимо было указать декоратор @parametrize на тестовой функции или реализовать хук pytest_generate_tests. pytest-2.3 вводит декоратор для использования на самой фабрике:
@pytest.fixture(params=["mysql", "pg"])
def db(request):
    ...  # use request.param
Здесь фабрика будет вызвана дважды (с соответствующими значениями «mysql» и «pg», установленными как атрибуты request.param), и все тесты, требующие «db», также будут запущены дважды.  Значения «mysql» и «pg» также будут использоваться для отчетов о вариантах вызова тестов.
Этот новый способ параметризации фабрик funcarg должен во многих случаях позволить повторно использовать уже написанные фабрики, поскольку эффективно request.param уже использовался при параметризации тестовых функций/классов через вызовы metafunc.parametrize(indirect=True).
Конечно, совершенно нормально сочетать параметризацию и скопинг:
@pytest.fixture(scope="session", params=["mysql", "pg"])
def db(request):
    if request.param == "mysql":
        db = MySQL()
    elif request.param == "pg":
        db = PG()
    request.addfinalizer(db.destroy)  # destroy when session is finished
    return db
Это позволит выполнить все тесты, требующие ресурс per-session «db» дважды, получая значения, созданные двумя соответствующими вызовами функции фабрики.
Отсутствие префикса pytest_funcarg__ при использовании декоратора @fixture¶
При использовании декоратора @fixture имя функции обозначает имя, под которым ресурс может быть доступен в качестве аргумента функции:
@pytest.fixture()
def db(request):
    ...
Имя, под которым может быть запрошен ресурс funcarg, - db.
Вы все еще можете использовать «старый» недекоративный способ указания funcarg-фабрик aka:
def pytest_funcarg__db(request):
    ...
Но тогда невозможно определить масштабирование и параметризацию. Поэтому рекомендуется использовать декоратор factory.
решение проблемы настройки на каждую сессию / автоматические приспособления¶
pytest долгое время предлагал хуки pytest_configure и pytest_sessionstart, которые часто используются для настройки глобальных ресурсов. Это страдает от нескольких проблем:
- при распределенном тестировании управляющий процесс будет устанавливать тестовые ресурсы, которые никогда не нужны, поскольку он только координирует деятельность рабочих процессов по выполнению тестов. 
- если вы выполняете только сбор (с параметром «–collect-only»), resource-setup все равно будет выполнен. 
- Если хук pytest_sessionstart содержится в некоторых подкаталогах файла conftest.py, он не будет вызван. Это связано с тем, что данный хук на самом деле используется для создания отчетов, в частности, test-header с информацией о платформе/настройках. 
Более того, было нелегко определить scoped setup из плагинов или файлов conftest, кроме как реализовать хук pytest_runtest_setup() и самостоятельно заботиться о scoping/caching.  И это практически невозможно сделать с параметризацией, поскольку pytest_runtest_setup() вызывается во время выполнения теста, а параметризация происходит во время сбора.
Из этого следует, что pytest_configure/session/runtest_setup часто не подходят для реализации общих потребностей в фикстурах. Поэтому в pytest-2.3 введены Автоматические светильники (светильники, которые не нужно запрашивать), которые полностью интегрируются с общими fixture mechanism и устаревают многие предыдущие применения крючков pytest.
funcargs/обнаружение приспособлений теперь происходит во время сбора материала¶
Начиная с pytest-2.3, обнаружение фабрик фикстур/функаргов происходит во время сбора. Это более эффективно, особенно для больших тестовых наборов. Более того, вызов команды «pytest –collect-only» в будущем сможет показать много информации о настройках и, таким образом, представляет собой хороший метод для получения общего представления об управлении фикстурами в вашем проекте.
Заключение и замечания по совместимости¶
funcargs были первоначально введены в pytest-2.0. В pytest-2.3 механизм был расширен и доработан и теперь описывается как фикстуры:
- ранее фабрики funcarg указывались со специальным префиксом - pytest_funcarg__NAMEвместо использования декоратора- @pytest.fixture.
- Фабрики получали объект - request, который управлял кэшированием через вызовы- request.cached_setup()и позволял использовать другие функарги через вызовы- request.getfuncargvalue(). Эти запутанные API затрудняли правильную параметризацию и реализацию кэширования ресурсов. Новый декоратор- pytest.fixture()позволяет объявить область видимости и позволить pytest разобраться во всем за вас.
- Если вы использовали фабрики параметризации и funcarg, которые использовали - request.cached_setup(), рекомендуется потратить несколько минут и упростить код функции приспособления, чтобы использовать декоратор Ссылка на светильники вместо него. Это также позволит воспользоваться преимуществами автоматической группировки тестов по ресурсам.