Share same instance of object to all tests (or modular tests) using combination of conftest.py
, fixtures and plain class
I'd like to share my solution, which comes from the Pytest documentation (7.2 currently)
Now, if we combine it with a conftest.py
this is what we could do:
First having this structure (just to show sub-module and that, object is instanciated once for all tests)
├── conftest.py
├── sub_folder
│ ├── __init__.py
│ └── test_sub_1.py
├── test_1.py
├── test_2.py
This is the content
conftest.py
"""tests/conftest.py"""
import pytest
class MockServer():
def get(self, url):
return "hello-world"
class App:
def __init__(self, http_connection):
print("APP CREATED")
self.http_connection = http_connection
@pytest.fixture(scope="session")
def http_connection():
print("HTTP_CONNECTION FIXTURE")
return MockServer()
@pytest.fixture(scope="session")
def app(http_connection):
print("CREATE APP")
return App(http_connection)
tests/test_1.py
class TestClass1:
def test_1(self, app):
http_connection = app.http_connection
assert http_connection.get("my-url") == "hello-world"
def test_2(self, app):
http_connection = app.http_connection
assert http_connection.get("my-url") == "hello-world"
tests/test_2.py
class TestClass2:
def test_1(self, app):
http_connection = app.http_connection
assert http_connection.get("my-url") == "hello-world"
def test_2(self, app):
http_connection = app.http_connection
assert http_connection.get("my-url") == "hello-world"
tests/sub_folder/test_sub_1.py
"""tests/sub_folder/test_sub_1.py"""
class TestSubClass1:
def test_sub_1(self, app):
http_connection = app.http_connection
assert http_connection.get("my-url") == "hello-world"
def test_sub_2(self, app):
http_connection = app.http_connection
assert http_connection.get("my-url") == "hello-world"
Now, lets run
pytest -rP
The output should be something like
tests/test_1.py::TestClass1::test_1 PASSED [ 16%]
tests/test_1.py::TestClass1::test_2 PASSED [ 33%]
tests/test_2.py::TestClass2::test_1 PASSED [ 50%]
tests/test_2.py::TestClass2::test_2 PASSED [ 66%]
tests/sub_folder/test_sub_1.py::TestSubClass1::test_sub_1 PASSED [ 83%]
tests/sub_folder/test_sub_1.py::TestSubClass1::test_sub_2 PASSED [100%]
==================================================================== PASSES ====================================================================
______________________________________________________________ TestClass1.test_1 _______________________________________________________________
------------------------------------------------------------ Captured stdout setup -------------------------------------------------------------
HTTP_CONNECTION FIXTURE
CREATE APP
APP CREATED
============================================================== 6 passed in 0.23s ===============================================================
As you can see, by the output, (HTTP_CONNECTION FIXTURE, CREATE APP, APP CREATED) is run only once. That's good when we need to share reasource across all tests.
Having said that, now let's combine it with hoefling answer, I only add tests/test_1.py
tests/test_1.py
"""tests/test_1.py"""
import pytest
class TestClass1:
@pytest.fixture(autouse=True)
def _app(self, app):
self.app = app
def test_1(self):
assert self.app.http_connection.get("my-url") == "hello-world"
def test_2(self):
assert self.app.http_connection.get("my-url") == "hello-world"
That's already better, but we can take it a step further, let's have a Base test class and having our test inherit from it
conftest.py
"""tests/conftest.py"""
import pytest
class MockServer():
def get(self, url):
return "hello-world"
class App:
def __init__(self, http_connection):
print("APP CREATED")
self.http_connection = http_connection
@pytest.fixture(scope="session")
def http_connection():
print("HTTP_CONNECTION FIXTURE")
return MockServer()
@pytest.fixture(scope="session")
def app(http_connection):
print("CREATE APP")
return App(http_connection)
class Base:
@pytest.fixture(autouse=True)
def _app(self, app):
self.app = app
Now """tests/test_1.py""" can look like
"""tests/test_1.py"""
from conftest import Base
class TestClass1(Base):
def test_1(self):
assert self.app.http_connection.get("my-url") == "hello-world"
def test_2(self):
assert self.app.http_connection.get("my-url") == "hello-world"