Pytest fixture with scope “class” doesn't works with “setup_class” method

China☆狼群 提交于 2021-01-28 01:52:56

问题


I'm currently using pytest_addoption to run my API tests, so the tests should run against the environment the user uses on the command line. In my test file, I'm trying to instantiate the UsersSupport class just once, passing the env argument. My code:

conftest.py

import pytest

# Environments
QA1 = 'https://qa1.company.com'
LOCALHOST = 'https://localhost'


def pytest_addoption(parser):
    parser.addoption(
        '--env',
        action='store',
        default='qa1'
    )


@pytest.fixture(scope='class')
def env(request):
    cmd_option = request.config.getoption('env')
    if cmd_option == 'qa1':
        chosen_env = QA1
    elif cmd_option == 'localhost':
        chosen_env = LOCALHOST
    else:
        raise UnboundLocalError('"--env" command line must use "qa1", "localhost"')
    return chosen_env

users_support.py

import requests


class UsersSupport:

    def __init__(self, env):
        self.env = env
        self.users_endpoint = '/api/v1/users'

    def create_user(self, payload):
        response = requests.post(
            url=f'{self.env}{self.users_endpoint}',
            json=payload,
        )
        return response

post_create_user_test.py

import pytest
from faker import Faker
from projects import UsersSupport
from projects import users_payload


class TestCreateUser:

    @pytest.fixture(autouse=True, scope='class')
    def setup_class(self, env):
        self.users_support = UsersSupport(env)
        self.fake = Faker()
        self.create_user_payload = users_payload.create_user_payload

    def test_create_user(self):
        created_user_res = self.users_support.create_user(
            payload=self.create_user_payload
        ).json()
        print(created_user_res)

The issue

When I run pytest projects/tests/post_create_user_test.py --env qa1 I'm getting AttributeError: 'TestCreateUser' object has no attribute 'users_support' error, but if I remove the scope from setup_class method, this method run on every method and not on all methods.

How can I use the env fixture in the setup_class and instantiate the UsersSupport class to use in all methods?


回答1:


If you use a fixture with class scope, the self parameter does not refer to the class instance. You can, however, still access the class itself by using self.__class__, so you can make class variables from your instance variables.

Your code could look like this:

import pytest
from faker import Faker
from projects import UsersSupport
from projects import users_payload


class TestCreateUser:

    @pytest.fixture(autouse=True, scope='class')
    def setup_class(self, env):
        self.__class__.users_support = UsersSupport(env)
        self.__class__.fake = Faker()
        self.__class__.create_user_payload = users_payload.create_user_payload

    def test_create_user(self):
        created_user_res = self.users_support.create_user(
            payload=self.create_user_payload
        ).json()  # now you access the class variable
        print(created_user_res)

During the test, a new test instance is created for each test.
If you have a default function scoped fixture, it will be called within the same instance of the test, so that the self arguments of the fixture and the current test refer to the same instance.

In the case of a class scoped fixture, the setup code is run in a separate instance before the test instances are created - this instance has to live until the end of all tests to be able to execute teardown code, so it is different to all test instances. As it is still an instance of the same test class, you can store your variables in the test class in this case.



来源:https://stackoverflow.com/questions/62289556/pytest-fixture-with-scope-class-doesnt-works-with-setup-class-method

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!