Use Session Scoped Fixture as Variable

I am writing tests in pytest and am using fixtures as variables.
Originally, this is how the fixtures looked:

@pytest.fixture(scope="class")
def user(request):
    u = "Matt"
    request.cls.u = u
    return u

And then, there was another fixture to delete the user from the database once I finished with it. In the tests, I used both fixtures like so @pytest.mark.usefixtures("user", "teardown fixture")
The teardown fixture was class scoped, until I decided to change it to session scoped, since I want to delete the user only after running all the tests.
The problem was that suddenly the teardown fixture couldn't access user, since user is class scoped.
I changed the user to session scoped, however, I am not sure how to access, or export it now.

@pytest.fixture(scope="session")
def user(request):
    u = "Matt"
    # request.cls.user = u -> WHAT GOES HERE INSTEAD OF THIS?
    return u

User is no longer recognized in the test functions.
The test is located inside of a class. The current function is something like this:

Class TestUser(OtherClassWhichInheritsFromBaseCase):
 def test_user1(self, user1):
        self.open("www.google.com")
        print(user1)

When I try to run the code in pycharm I get the following error:

def _callTestMethod(self, method):
>       method()
E       TypeError: TestUser.test_user1() missing 1 required positional argument: 'user1'

Any advice?


I think you're approaching this from the wrong direction. If you need to clean up a fixture, you don't write a second fixture; you write your fixture as a context manager.

For example, you might write:

@pytest.fixture(scope="session")
def user():
    u = User(name="Matt")
    yield u
    # cleanup goes here

And in your test code:

def test_something(user):
  assert user.name == "Matt"

Here's a complete example. We start with this dummy user.py, which simply creates files to demonstrate which methods were called:

from dataclasses import dataclass


@dataclass
class User:
    name: str

    def commit(self):
        open("commit_was_called", "w")

    def delete(self):
        open("delete_was_called", "w")

Then here's our test:


import pytest

import user


@pytest.fixture(scope="session")
def a_user():
    u = user.User(name="testuser")
    u.commit()
    yield u
    u.delete()


class TestUserStuff:
    def test_user(self, a_user):
        assert a_user.name == "testuser"

We run it like this:

$ pytest
=============================================================================================== test session starts ===============================================================================================
platform linux -- Python 3.10.1, pytest-6.2.4, py-1.11.0, pluggy-0.13.1
rootdir: /home/lars/tmp/python
plugins: testinfra-6.5.0
collected 1 item

test_user.py .                                                                                                                                                                                              [100%]

================================================================================================ 1 passed in 0.00s ================================================================================================

After which we can confirm that both the commit and delete methods were called:

$ ls
commit_was_called
delete_was_called
test_user.py
user.py