简体   繁体   中英

pytest: Assigning attribute in a fixture not visible to test cases

Why am I unable to set a self.param value in a pytest fixture?


class TestClass:
    @pytest.fixture(scope='class', autouse=True)
    def setup_class(self, test_env):
        self.param = 2

    def teardown_method(self):
        remove_setting(self.param)
    
    def test_one(self):
        assert self.param == 2

    def test_two(self):
        assert len("hello") == 5

This results in

scratch.py::TestClass::test_one FAILED                                 

    def test_one(self):
>       assert self.param == 2
E       AttributeError: 'TestClass' object has no attribute 'param'

    def teardown_method(self):
>       remove_setting(self.param)
E       AttributeError: 'TestClass' object has no attribute 'param'

I want to set this attribute during the setup because I will eventually execute a method-level teardown with that parameter (NOT a class-level teardown, so I didn't use yield). In this example, my tests can't see the self.param value and neither can my teardown function. It is cumbersome to move self.param = 2 into all of my tests. What's a better way to do this?

As docs says:

Something to be aware of when grouping tests inside classes is that each test has a unique instance of the class . Having each test share the same class instance would be very detrimental to test isolation and would promote poor test practices.

I would suggest to use class scope fixture like this:

import pytest

@pytest.fixture(scope='module')
def test_env():
    pass

@pytest.fixture(scope='class')
def param(test_env):
    return 2


class TestClass:
    def test_one(self, param):  # All tests methods share the same param
        assert param == 2

    def test_two(self, param):
        assert param == 3

You are trying to achieve the classic xunit-style setup , so I'm not quite sure on the purpose of having the setup being a pytest fixture. So one solution would be the following code snippet:

class TestClass:
    @classmethod
    def setup_class(cls):
        cls.param = 2

    def test_one(self):
        assert self.param == 2

Although if you're looking to use pytest fixtures , you can make a fixture and pass it in as a parameter through the tests that you need it in, which I believe is more in-line with how pytest intends for fixtures to be used:

import pytest

@pytest.fixture
def my_param():
    return 2

class TestClass:
    def test_one(self, my_param):
        assert my_param == 2

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