Когда я помещаю свои приборы в 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__