简体   繁体   中英

Pytest “run-around-tests” fixture to run only once before all tests in a class

I am testing the User message function of a web solution using pytest + selenium. The tests will generate a test message to a test user, and then log in that user to verify that the message indeed is displaying for that user.

  • I need to generate those messages through an internal API.
  • In order to be able to access this API, I first have to generate an AUTH token through a different API.

So the test scenario is basically:

  1. At test startup, generate a new AUTH token through an API helper function.
  2. Send a request to another API to set a new message (requires the AUTH token)
  3. Send a request to yet another API to "map" this message to a specified user (requires the AUTH token)
  4. Log in test user and verify that the new message is indeed displaying.

My problem is that I want to avoid creating a new AUTH token every time every test within my test class is run - I want to create a new token once that all tests use within the same test run.

What is the smartest solution to generate one new access token when invoking all tests?

Right now I have come up with something like this, which will generate a new token every time any individual test is run:

import pytest
import helpers.api_access_token_helper as token_helper
import helpers.user_message_generator_api_helper as message_helper
import helpers.login_helper as login_helper
import helpers.popup_helper as popup_helper

class TestStuff(object):

    @pytest.yield_fixture(autouse=True)
    def run_around_tests(self):
        yield token_helper.get_api_access_token()

    def test_one(self, run_around_tests):
        auth_token = run_around_tests
        message_helper.create_new_message(auth_token, some_message_data)
        message_helper.map_message_to_user(auth_token, user_one["user_id"])
        login_helper.log_in_user(user_one["user_name"], user_one["user_password"])
        assert popup_helper.user_message_is_displaying(some_message_data["title"])

    def test_two(self, run_around_tests):
        auth_token = run_around_tests
        message_helper.create_new_message(auth_token, some_other_message_data)
        message_helper.map_message_to_user(auth_token, user_two["user_id"])
        login_helper.log_in_user(user_two["user_name"], user_two["user_password"])
        assert popup_helper.user_message_is_displaying(some_other_message_data["title"])

I have laborated back and forth a bit with the "run-around-tests" fixture but havent been able to find a solution.

You have to adapt the fixture scope to cache its results for all tests in test run ( scope='session' ), all tests in module ( scope='module' ), all tests in class (old unittest -style tests only, scope='class' ), or for a single test ( scope='function' ; this the default one). Examples:

fixture function

@pytest.fixture(scope='session')
def token():
    return token_helper.get_api_access_token()


class Tests(object):

    def test_one(self, token):
        ...

    def test_two(self, token):
        ...


class OtherTests(object):

    def test_one(self, token):
        ...

The token will be calculated once when first requested and kept in cache throughout the whole test run, so all three tests Tests::test_one , Tests::test_two and OtherTests::test_one will share the same token value.

fixture class method

If you intend to write old-style test classes instead of test functions and want the fixture to be a class method (like it is in your code), note that you can only use the class scope, so that the fixture value is shared only between the tests in the class:

class TestStuff(object):

    @pytest.fixture(scope='class')
    def token(self):
        return token_helper.get_api_access_token()

    def test_one(self, token):
        ...

    def test_two(self, token):
        ...

Stuff aside:

  1. pytest.yield_fixture is deprecated and replaced by pytest.fixture ;
  2. you don't need to set autouse=True because you explicitly request the fixture in the test parameters. It will be called anyway.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM