Когда я помещаю свои приборы в conftest.py (что является предпочтительным способом повторного использования приборов в проекте), я натыкаюсь на одну небольшую проблему: прибор больше не может использовать __file__ для поиска каталога, в котором присутствует файл.

Обычный способ в Python увидеть «собственный» каталог — использовать

os.path.dirname(__file__)

(Он использует магическую переменную __file__ с именем файла текущего модуля, в котором выполняется код). По очевидным причинам, когда прибор перемещается (например) из /foo/bar/tests_slow/test_slow.py в /foo/bar/conftest.py, содержимое __file__ меняется.

Почему кто-то хочет использовать эту «магию»?

Основная причина — получить файлы относительно тестового файла:

.
├── conftest.py
└── some_tests
    ├── data.json
    └── test_some.py

Я хочу получить доступ к data.json из прибора. Когда прибор находится в test_some, я просто делаю os.path.join(os.path.dirname(__file__), "data.json"). Это прерывается, если прибор перемещается на conftest.py .

Решение

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

Есть волшебная фикстура request (не библиотека requests! Здесь немного коллизии), которая содержит всю информацию о текущем тесте и построении фикстуры. И у него есть «модуль», то есть модуль с тестом. И у этого модуля есть собственная волшебная переменная __file__, которая является нужной информацией.

Таким образом, содержимое фикстуры fixture1 внутри conftest.py:

@pytest.fixture()
def fixture1(request):
    test_dir = os.path.dirname(request.module.__file__)
    data_filename = os.path.join(test_dir, "data.json")
    with open(data_filename, "r") as f:
        return json.load(f)

Если у вас есть цепочка приборов, можно добавить request в любой момент:

@pytest.fixture()
def complicated_fixture(fixture1, fixture2, fixture2, request):
    ...

Дополнительное примечание: вы можете передать request в качестве прибора в свой тест, но на мой вкус это слишком много самоанализа.

Обновление: если вы когда-нибудь решите пойти pytest_generate_tests путем, он тоже там:

metafunc.module.__file__