Pytest: Can pytest hooks use fixtures?

Created on 29 Mar 2019  路  10Comments  路  Source: pytest-dev/pytest

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".

Version:

platform win32 -- Python 3.7.2, pytest-4.3.1, py-1.8.0, pluggy-0.9.0

question

All 10 comments

Oh fun, I answered you on stackoverflow https://stackoverflow.com/a/55416498/812183

Oh fun, I answered you on stackoverflow https://stackoverflow.com/a/55416498/812183

Yeah, but that doesn't answer my question. Please check my comment there.

I need pytest_runtest_setup hook to be able to use json_loader fixture. Is there any way for that? If not, why is that not allowed so?

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?

The short answer is "no", and there's no easy way to include that support as well because hooks don't have scope by definition, while fixtures are directly tied to a scope. Hooks might be called at any point in the session, and might be called externally in any order also.

I've often found that one doesn't need fixtures in hooks, just need to approach the problem differently. Often using an autouse fixture you can get by the need to execute code before test setup for example, by per your snippet.

The short answer is "no", and there's no easy way to include that support as well because hooks don't have scope by definition, while fixtures are directly tied to a scope. Hooks might be called at any point in the session, and might be called externally in any order also.

I've often found that one doesn't need fixtures in hooks, just need to approach the problem differently. Often using an autouse fixture you can get by the need to execute code before test setup for example, by per your snippet.

Thanks for the information.

I had actually used 'autouse' fixture before to get this work done before every test run. But then, I realized I should be using 'pytest_runtest_setup' hook to make it look more neat and to justify the purpose of this hook. Also any new team member would easily understand if I had used this hook rather than trying to accomplish the same using 'autouse' fixture, as he would obviously know what this hook is used for.

Having said this, it would be helpful if you could share your views on this? Does my above thought make sense? If yes, should we raise a bug asking for a feature where hooks can use fixtures?
Thanks in advance.

Just for eg:, I can still use 'pytest_runtest_setup' in my design but then I would have to re-write the code for json loading. That means we would be duplicating that code when simply I could have utilized 'json_loader' fixture.

I had actually used 'autouse' fixture before to get this work done before every test run. But then, I realized I should be using 'pytest_runtest_setup' hook to make it look more neat and to justify the purpose of this hook. Also any new team member would easily understand if I had used this hook rather than trying to accomplish the same using 'autouse' fixture, as he would obviously know what this hook is used for.

Not sure, in my view hooks are more advanced than fixtures, so fixture-based solutions are generally easier to understand by most users.

If yes, should we raise a bug asking for a feature where hooks can use fixtures?

I don't think this would work, fixtures and hooks have different semantics; trying to make hooks access fixtures (without hacks I mean) might be hard to do and raise all kind of problems.

Just for eg:, I can still use 'pytest_runtest_setup' in my design but then I would have to re-write the code for json loading. That means we would be duplicating that code when simply I could have utilized 'json_loader' fixture.

In many cases you can extract the code from the fixture to a simple function, and just call that function from the fixture. This way you don't duplicate any code.

In many cases you can extract the code from the fixture to a simple function

I think what you mean by this is to convert the fixture to a normal function.

Eg : In my case, I will remove the fixture tag from json_loader() to make it a normal function that can be imported by the hook. (Maybe I will place json_loader() in a new module now so that I do not put non-fixture functions in conftest.py and hence maintain neatness).

Is my understanding right? If not, can you please explain with some example?

Yes, that's it. It seems json_loader does not need to be a fixture anyway and a normal function will do just fine. 馃憤

If you are happy with the answer, could you close the issue? Thanks.

Cool. Thanks.

I hoped this was really answered. My requirement is that: I want to use request fixture in a hook.
Any hack or good solution around this?

@Azee77 Like @nicoddemus mentioned above, fixtures exists for a given test, while hooks are a more "global" thing, so there's no way how this would work. What do you need from the request fixture, in which hook, and what's your goal?

Was this page helpful?
0 / 5 - 0 ratings