-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
Description
Hi,
I'm trying to build a base class to hold a common test setup and assumptions, that I want to enable in subclasses (inspired by this article) having the fixture-powered setup be dependent on class variables. However this approach clashes with class-scoped fixtures which are not run in subclasses of test classes, so any effect or class variables initialized there are not available. I don't know if it's a feature or a bug.
I wonder if this is a bug, if the fixtures should be called in __init_subclass__() for example. Or maybe if an additional "subclass" scope would be of interest or just legit to have?
Here a concrete example, modifying the code from the docs https://docs.pytest.org/en/stable/how-to/fixtures.html#running-multiple-assert-statements-safely
I'm also open to any other suggestion to get a similar result. Passing fixtures as subclasses variable was also not successful.
# contents of tests/end_to_end/test_login.py
from unittest.mock import MagicMock
from urllib.parse import urljoin
from uuid import uuid4
import pytest
Chrome = MagicMock()
AdminApiClient = MagicMock()
User = MagicMock()
LandingPage = MagicMock()
LoginPage = MagicMock()
@pytest.fixture(scope="class")
def admin_client(base_url, admin_credentials):
return AdminApiClient(base_url, **admin_credentials)
@pytest.fixture(scope="class")
def user(admin_client):
_user = User(name="Susan", username=f"testuser-{uuid4()}", password="P4$$word")
admin_client.create_user(_user)
yield _user
admin_client.delete_user(_user)
@pytest.fixture(scope="class")
def driver():
_driver = Chrome()
yield _driver
_driver.quit()
@pytest.fixture(scope="class")
def landing_page(driver, login):
return LandingPage(driver)
class TestLandingPageSuccessBase:
__test__ = False # Hide from test discovery
def __init_subclass__(cls, **kwargs):
super().__init_subclass__(**kwargs)
cls.__test__ = True # Enable test discovery for subclasses
api_version: str # To be defined in subclasses
# Unfortunately, login is not called in subclasses!!!
@pytest.fixture(scope="class", autouse=True)
def login(self, driver, base_url, user):
driver.get(urljoin(base_url, f"/{self.api_version}/login"))
page = LoginPage(driver)
page.login(user)
def test_name_in_header(self, landing_page, user):
assert landing_page.header == f"Welcome, {user.name}!"
def test_sign_out_button(self, landing_page):
assert landing_page.sign_out_button.is_displayed()
def test_profile_link(self, base_url, landing_page, user):
profile_href = urljoin(base_url, f"/profile?id={user.profile_id}")
assert landing_page.profile_link.get_attribute("href") == profile_href
class TestLandingPageSuccessV1(TestLandingPageSuccessBase):
api_version: str = 'v1'
class TestLandingPageSuccessV2(TestLandingPageSuccessBase):
api_version: str = 'v2'Running locally on Python 3.14.0 and pytest 8.4.2.