Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

pytest fixture is always returning a function

I want to be able to return a value from a fixture to multiple tests/test classes, but the value that gets passed is a function.

Here's my code:

import pytest

@pytest.fixture()
def user_setup():
    user = {
        'name': 'chad',
        'id': 1
    }
    return user

@pytest.mark.usefixtures('user_setup')
class TestThings:
    def test_user(self):
        assert user_setup['name'] == 'chad'

The output is:

=================================== FAILURES ===================================
_____________________________ TestThings.test_user _____________________________

self = <tests.test_again.TestThings instance at 0x10aed6998>

    def test_user(self):
>       assert user_setup['name'] == 'chad'
E       TypeError: 'function' object has no attribute '__getitem__'

tests/test_again.py:14: TypeError
=========================== 1 failed in 0.02 seconds ===========================

But if I rewrite my test so that it doesn't use the usefixtures decorator, it works as expected:

def test_user(user_setup):
    assert user_setup['name'] == 'chad'

Any ideas why it's not working when I try to use the decorator method?

like image 502
Cass Avatar asked Aug 28 '14 22:08

Cass


1 Answers

When you use the @pytest.mark.usefixtures marker you still need to provide a similarly named input argument if you want that fixture to be injected in to your test function.

As described in the py.test docs for fixtures:

The name of the fixture function can later be referenced to cause its invocation ahead of running tests... Test functions can directly use fixture names as input arguments in which case the fixture instance returned from the fixture function will be injected.

So just using the @pytest.mark.usefixtures decorator will only invoke the function. Providing an input argument will give you the result of that function.

You only really need to use @pytest.mark.usefixtures when you want to invoke a fixture but don't want to have it as an input argument to your test. As described in the py.test docs.

The reason you are getting an exception that talks about user_setup being a function is because inside your test_user function the name user_setup actually refers to the function you defined earlier in the file. To get your code to work as you expect you would need to add an argument to the test_user function:

@pytest.mark.usefixtures('user_setup')
class TestThings:
    def test_user(self, user_setup):
        assert user_setup['name'] == 'chad'

Now from the perspective of the test_user function the name user_setup will refer to the function argument which will be the returned value of the fixture as injected by py.test.

But really you just don't need to use the @pytest.mark.usefixtures decorator at all.

like image 77
Jeremy Allen Avatar answered Oct 21 '22 08:10

Jeremy Allen