Reputation: 34185
In test_something()
, the app
instance should be the same as used by the login
instance.
@pytest.fixture
def app():
# ...
return app
@pytest.fixture
def login(app):
# ...
return login
def test_something(self, app, login):
pass
What I tried is returning both objects from the second fixture, but I wouldn't call this idiomatic.
@pytest.fixture
def app_and_login(app):
# ...
return app, login
def test_something(self, app_and_login):
app, login = login_and_login
Is there a better way to do this?
Upvotes: 4
Views: 2886
Reputation: 29906
I know this question is old, but I'm not seeing the behavior you describe, and I got really sidetracked by this Q&A until I thought, "It can't work that way..." and tested it out for myself. I tried this on:
platform darwin -- Python 3.7.7, pytest-6.0.1, py-1.9.0, pluggy-0.13.1 -- .../bin/python3
I made this test, and it passes:
import collections
import pytest
AppObject = collections.namedtuple("App", ["name", "login"])
@pytest.fixture
def app():
app = AppObject("appname", "applogin")
return app
@pytest.fixture
def login(app):
return app.login
def test_something(app, login):
assert isinstance(app, AppObject) and app.name == "appname"
assert isinstance(login, str) and login == "applogin"
OP seems concerned about the app
object being received by the login
fixture being different from the app
returned by the app fixture. I don't see that happening. For instance, if you add some helpful print
statements like this:
import collections
import pytest
AppObject = collections.namedtuple("App", ["name", "login"])
@pytest.fixture
def app():
app = AppObject("appname", "applogin")
print("Object id in app fixture: %d" % id(app))
return app
@pytest.fixture
def login(app):
print("Object id in login fixture: %d" % id(app))
return app.login
def test_something(app, login):
print("Object id in test: %d" % id(app))
assert isinstance(app, AppObject) and app.name == "appname"
assert isinstance(login, str) and login == "applogin"
I see this output:
Object id in app fixture: 4451368624
Object id in login fixture: 4451368624
Object id in test: 4451368624
...so it's definitely the same object in all three places. Nested fixtures like this "just work" for me, so I'm either missing the point of the question you were asking, or behavior has changed, or... something else. But I wanted to leave this here for others who come along looking for nested/dependent fixtures like this.
Upvotes: 0
Reputation: 11939
As you described, the fixture already is shared for the runtime of the test by default.
This isn't really documented explicitly anywhere (or at least I haven't found it), but it's somewhat implicit: Sharing a fixture across tests in a module describes the scope
parameter, and the default scope is function
.
Other scopes would e.g. be module
(share/cache the fixture for all tests in the same module) or session
(cache the fixture for the whole test session).
Upvotes: 2
Reputation: 2362
You can return it as object, and use third fixtue:
import pytest
from collections import namedtuple
Auth = namedtuple('Auth', 'app, login')
@pytest.fixture
def app():
return 'APP'
@pytest.fixture
def login(app):
return 'Login at %s' % app
@pytest.fixture
def auth(app, login):
return Auth(app, login)
def test_something(auth):
assert auth.app in auth.login
Upvotes: 0
Reputation: 34185
I didn't expect this but it seems to be the default behavior. I couldn't find any documentation about this though. Hints are appreciated.
Upvotes: 0