Skip to content

class-scoped fixtures VS test subclasses #13882

@MRigal

Description

@MRigal

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    status: needs informationreporter needs to provide more information; can be closed after 2 or more weeks of inactivity

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions