Reputation: 121
I know fixtures can use other fixtures, but can a hook use a fixture? I searched a lot on net but could not get any help. Can someone please point if I am doing any mistake here?
#conftest.py
@pytest.fixture()
def json_loader(request):
"""Loads the data from given JSON file"""
def _loader(filename):
import json
with open(filename, 'r') as f:
data = json.load(f)
return data
return _loader
def pytest_runtest_setup(item,json_loader): #hook fails to use json_loader
data = json_loader("some_file.json")
print(data)
#do something useful here with data
I get the following error when I run it.
pluggy.manager.PluginValidationError: Plugin 'C:\some_path\conftest.py' for hook 'pytest_runtest_setup' hookimpl definition: pytest_runtest_setup(item, json_loader) Argument(s) {'json_loader'} are declared in the hookimpl but can not be found in the hookspec
Even if I do not pass json_loader as an arg to pytest_runtest_setup(), I get an error saying "Fixture "json_loader" called directly. Fixtures are not meant to be called directly"
Upvotes: 12
Views: 12872
Reputation: 87
You can do something like this:
@pytest.fixture
def my_fixture():
pass
@pytest.mark.hookwrapper
def my_hook(item):
feature_request = item.funcargs["request"]
my_fixt = feature_request.getfixturevalue("my_fixture")
Upvotes: 0
Reputation: 45
There is a way where you can get the used fixture from a test.
#Conftest.py#
def pytest_runtest_makereport(item, call):
if call.when == 'call':
cif_fixture = item.funcargs["your_cool_fixture"]
print(cif_fixture)
#test_file.py#
@pytest.fixture(scope="module")
def your_cool_fixture(request):
return "Hi from fixture"
def test_firsttest(your_cool_fixture):
print(your_cool_fixture)
Upvotes: 2
Reputation: 69914
It seems the only current supported way to dynamically instantiate fixtures is via the request
fixture, specifically the getfixturevalue
method
This isn't accessible before test time in a pytest hook, but you can accomplish the same by using a fixture yourself
Here's a (contrived) example:
import pytest
@pytest.fixture
def load_data():
def f(fn):
# This is a contrived example, in reality you'd load data
return f'data from {fn}'
return f
TEST_DATA = None
@pytest.fixture(autouse=True)
def set_global_loaded_test_data(request):
global TEST_DATA
data_loader = request.getfixturevalue('load_data')
orig, TEST_DATA = TEST_DATA, data_loader(f'{request.node.name}.txt')
yield
TEST_DATA = orig
def test_foo():
assert TEST_DATA == 'data from test_foo.txt'
Upvotes: 4