Pytest: Defining a fixture in `pytest_configure` (dynamic arguments)

Created on 2 Apr 2019  Â·  7Comments  Â·  Source: pytest-dev/pytest

I've tried to define a fixture based on a config option:

def pytest_addoption(parser):
    group = parser.getgroup('myplugin')

    group.addoption(
        '--myplugin-autouse',
        action='store_false',
        dest='myplugin_autouse',
        help="Autouse the myplugin fixture.",
    )


def pytest_configure(config):
    autouse = config.option.myplugin_autouse

    @pytest.fixture(scope="function", autouse=autouse)
    def myplugin_fix():
        …
        yield w
        …

But it appears to not be available then.

Is there a way to achieve this?

question

Most helpful comment

That works - I must have missed something when trying this before..

I am using an entrypoint plugin, and this results in two plugins effectively (also via conftest), but I assume there is no way around this really (don't want to mock around with patching the first plugin really for now ;))

All 7 comments

Plugin class you then register?

Tried to use a Plugin class quickly, but it looked like fixtures where not used from there - but I have not really investigated.. would fixtures be decorated class methods then?
(another solution would be using hooks I guess)

This works for me:

# conftest.py
import pytest

def pytest_configure(config):

    class Plugin:

        @pytest.fixture(autouse=True)
        def fix(self):
            assert 0

    config.pluginmanager.register(Plugin())

That works - I must have missed something when trying this before..

I am using an entrypoint plugin, and this results in two plugins effectively (also via conftest), but I assume there is no way around this really (don't want to mock around with patching the first plugin really for now ;))

It turns out that "self" is the test class when used there..?!

def test(testdir):
    testdir.makeconftest(
        """
        import pytest

        class Plugin:

            @pytest.fixture
            def fix(self):
                print("out_fix", self)
                assert self.__class__ == Plugin


        def pytest_configure(config):
            config.pluginmanager.register(Plugin())
        """
    )
    p1 = testdir.makepyfile(
        """
        class Test:
            def test(self, fix):
                pass
    """)
    result = testdir.runpytest(str(p1), "-s")
    stdout = result.stdout.str()
    assert "out_fix" in stdout
    assert result.ret == 0
_________________________ ERROR at setup of Test.test __________________________

self = <test.Test object at 0x7f4283b85b38>

    @pytest.fixture
    def fix(self):
        print("out_fix", self)
>       assert self.__class__ == Plugin
E       AssertionError: assert <class 'test.Test'> == Plugin
E        +  where <class 'test.Test'> = <test.Test object at 0x7f4283b85b38>.__class__

conftest.py:8: AssertionError
=========================== 1 error in 0.03 seconds ============================

Strange, this works for me:

# conftest.py
import pytest


def pytest_configure(config):

    class Plugin:

        @pytest.fixture(autouse=True)
        def fix(self):
            assert type(self) is Plugin

    config.pluginmanager.register(Plugin())

# test_foo.py
def test(fix):
    pass

This passes for me, and to make sure fix was being called I added assert 0 after assert type(self) is Plugin just to make sure that code was being reached, and the assert 0 did fail.

since his case is when having a class at that, i propose adding a test for both cases, and then sorting the xfail later on

Was this page helpful?
0 / 5 - 0 ratings