Pytest fixture for a class through self not as method argument

I had to solve a similar problem and the accepted solution didn't work for me with a class-scoped fixture.

I wanted to call a fixture once per test class and re-use the value in test methods using self. This is actually what the OP was intending to do as well.

You can use the request fixture to access the class that's using it (request.cls) and assign the fixture value in a class attribute. Then you can access this attribute from self. Here's the full snippet:

from bs4 import BeautifulSoup
import pytest
import requests

@pytest.fixture(scope="class")
def google(request):
    request.cls.google = requests.get("https://www.google.com")


@pytest.mark.usefixtures("google")
class TestGoogle:
    def test_alive(self):
        assert self.google.status_code == 200

    def test_html_title(self):
        soup = BeautifulSoup(self.google.content, "html.parser")
        assert soup.title.text.upper() == "GOOGLE"

Hope that helps anyone else coming to this question.


Sure, just use an autouse fixture. Here is the relevant spot in pytest docs. In your example, the change would be introducing an extra fixture (I named it _request_google_page):

from bs4 import BeautifulSoup
import pytest
import requests

@pytest.fixture()
def google():
    return requests.get("https://www.google.com")


class TestGoogle:

    @pytest.fixture(autouse=True)
    def _request_google_page(self, google):
        self._response = google

    def test_alive(self):
        assert self._response.status_code == 200

    def test_html_title(self):
        soup = BeautifulSoup(self._response.content, "html.parser")
        assert soup.title.text.upper() == "GOOGLE"

You could even drop the google fixture completely and move the code to _request_google_page:

@pytest.fixture(autouse=True)
def _request_google_page(self):
    self._response = requests.get("https://www.google.com")

Note that _request_google_page will be called once per test by default, so each test will get a new response. If you want the response to be initialized once and reused throughout all tests in the TestGoogle class, adjust the fixture scopes (scope='class' for _request_google_page and scope='module' or scope='session' for google). Example:

from bs4 import BeautifulSoup
import pytest
import requests


@pytest.fixture(scope='module')
def google():
    return requests.get("https://www.google.com")


@pytest.fixture(autouse=True, scope='class')
def _request_google_page(request, google):
    request.cls._response = google


class TestGoogle:

    def test_alive(self):
        assert self._response.status_code == 200

    def test_html_title(self):
        soup = BeautifulSoup(self._response.content, "html.parser")
        assert soup.title.text.upper() == "GOOGLE"