Reputation: 1
I need to create a PyTest plugin, which can dynamically create fixtures (and add them to existing tests).
Specifically I have a use case to support some legacy test setup and teardown hooks from a PyTest plugin.
I'm attempting to create a PyTest hook which 1) dynamically creates a new fixture, 2) injects the fixture into the test module, and 3) makes relevant test cases use the fixture.
I'm awear of the pytest_runtest_setup
and pytest_runtest_teardown
hooks, for running code before and after tests - however I also need to support module scope fixtures.
I've based my code on a previous PyTest discussion, which I've tested and showen to work when it runs inside the test module - however running from the PyTest plugin results in the test not being discovered.
Minimum reproducible example:
plugin.py
def pytest_collection_modifyitems(items: List[Item]):
for item in items:
if not isinstance(item, Function):
continue
pytest_function: Function = item.getparent(Function)
def _generate_fixture(name: str):
@pytest.fixture(name=name)
def _fixture():
print("Setup...")
yield
print("Teardown...")
return _fixture
def inject_fixture(name: str, module: ModuleType):
setattr(module, name, _generate_fixture(name))
inject_fixture("example_fixture", pytest_function.module)
pytest_function: Function = item.getparent(Function)
pytest_function.fixturenames.append("example_fixture")
test_dummy.py
def test_dummy_func():
print(globals())
pass
Expected behaviour: The setup and tear-down prints are executed, observed with pytest test_dummy.py -r P
Actual behaviour: The fixture is not discovered:
============================ ERRORS =============================
_______________ ERROR at setup of test_dummy_func _______________
file /local/home/harleyip/workspaces/LambdaWorkerPythonTestDriver/src/LambdaWorkerPythonTestDriver/test_dummy.py, line 3
def test_dummy_func():
E fixture 'example_fixture' not found
> available fixtures: cache, capfd, capfdbinary, caplog, capsys, capsysbinary, doctest_namespace, monkeypatch, pytestconfig, record_property, record_testsuite_property, record_xml_attribute, recwarn, tmp_path, tmp_path_factory, tmpdir, tmpdir_factory
> use 'pytest --fixtures [testpath]' for help on them.
Disabling the fixture, and printing globals()
from the integration test, shows the "fixture" is in the globals:
----------Captured stdout call--------------
...
'example_fixture': <function pytest_collection_modifyitems.<locals>.generate_fixture.<locals>._fixture at 0x7fc6336daf70>}
...
Upvotes: 0
Views: 174
Reputation: 1
Turns out PyTest makes this simple, but doesn't document it anywhere. Putting the fixture directly the plugin script makes the fixture accessable to the tests:
@pytest.fixture(autouse=True, scope="module")
def legacy_test_module_hooks():
print("Setup...")
yield
print("Teardown...")
Upvotes: 0