Search code examples
pythonflaskpytest

Writing pytest with JWT token in class


I have a class TestSecured and in it, I have methods that will get endpoints that are protected, so you need a jwt to make a request. I am trying to optimize my test class so that I don't need to do the login process 3 times but only 1 and use the same token in my 3 tests method.

@pytest.mark.usefixtures("client", "auth", "setup_user_and_token")
class TestSecured:
        

    def test_get_operations(self, client, setup_user_and_token):
        # headers = {'Authorization' : f'Beare {setup_user_and_token}'}
        response = client.get(f'{SECURED_ROUTE}get-operations', headers=setup_user_and_token)
        assert response.status_code == 200

    def test_post_operation(self, client, auth):
        return "ok"


    def test_post_ope2(self,client,auth):
        print("ok")

It works if I set headers in each method with the setup_user_and_token() fixture I created.

@pytest.fixture(scope="class")
def setup_user_and_token(auth):
    response = auth.login()
    token = response.get_json()['access_token']
    return {'Authorization' : f'Bearer {token}'}

But I want to use the setup_class() to do this only once. How can I achieve this?

EDIT: Below it is my conftest.py file where I defined some fixtures:

@pytest.fixture
def app():
    app = create_app({
        'TESTING' : True,
    })
    yield app
   
    with app.app_context():
        db.drop_all()


@pytest.fixture
def client(app):
    return app.test_client()


class AuthActions(object):
    def __init__(self, client):
        self._client = client

    def login(self, username='test_user', password='test_pass'):
        return self._client.post(
            '/auth/login',
            json={'username': username, 'password': password}
        )

    def logout(self):
        return self._client.get('/auth/logout')

def auth(client):
    return AuthActions(client)

@pytest.fixture(scope="class")
def setup_user_and_token(auth):
    response = auth.login()
    token = response.get_json()['access_token']
    return {'Authorization' : f'Bearer {token}'}

Solution

  • You can add a fixture to the test class and use the fixtures there

    class TestSecured:
    
        @pytest.fixture(scope="class", autouse=True)
        def setup_class(self, setup_user_and_token, client, auth):
            TestSecured.__setup_user_and_token = setup_user_and_token
            TestSecured.__client = client
            TestSecured.__auth = auth
    
        def test_get_operations(self):
            # headers = {'Authorization' : f'Beare {setup_user_and_token}'}
            response = client.get(f'{SECURED_ROUTE}get-operations', headers=self.__setup_user_and_token)
            assert response.status_code == 200
    
        def test_post_operation(self):
            # do something with self.__client
            # do something with self.__auth
            return "ok"
    
        def test_post_ope2(self):
            print("ok")
    

    You should also remove the usefixtures marker, you use it or call the fixtures directly, see reference.