How to accumulate state through tests in py.test

I currently have a project and tests similar to them.

class mylib:
    @classmethod
    def get_a(cls):
        return 'a'

    @classmethod
    def convert_a_to_b(cls, a):
        return 'b'

    @classmethod
    def works_with(cls, a, b):
        return True

class TestMyStuff(object):
    def test_first(self):
        self.a = mylib.get_a()

    def test_conversion(self):
        self.b = mylib.convert_a_to_b(self.a)

    def test_a_works_with_b(self):
        assert mylib.works_with(self.a, self.b)

With py.test 0.9.2, these tests (or similar) pass. With later versions, py.test, test_conversion and test_a_works_with_b fail with 'TestMyStuff does not have an attribute a'.

I assume that this is due to the fact that subsequent builds of py.test create a separate instance of TestMyStuff for each method being tested.

What is the correct way to record these tests so that the results can be given for each stage of the sequence, but can the state from the previous (successful) test be used to perform subsequent tests?

+3
source share
4

unit test , , . unit test , . , , . , .

+8

, . , .

py.test , , . :

class State:
    """ holding (incremental) test state """

def pytest_funcarg__state(request):
    return request.cached_setup(
        setup=lambda: State(),
        scope="module"
    )

class mylib:
    @classmethod
    def get_a(cls):
        return 'a'

    @classmethod
    def convert_a_to_b(cls, a):
        return 'b'

    @classmethod
    def works_with(cls, a, b):
        return True

class TestMyStuff(object):
    def test_first(self, state):
        state.a = mylib.get_a()

    def test_conversion(self, state):
        state.b = mylib.convert_a_to_b(state.a)

    def test_a_works_with_b(self, state):
        mylib.works_with(state.a, state.b)

py.test. "", "funcarg" factory . py.test , , , "".

, , , "test_conversion" , , "py.test -k test_conversion", , . , , , , .

,

+6

, , pytest: https://docs.pytest.org/en/latest/fixture.html

, //. , , .

, :

import pytest


class State:

    def __init__(self):
        self.state = {}


@pytest.fixture(scope='session')
def state() -> State:
    state = State()
    state.state['from_fixture'] = 0
    return state


def test_1(state: State) -> None:
    state.state['from_test_1'] = 1
    assert state.state['from_fixture'] == 0
    assert state.state['from_test_1'] == 1


def test_2(state: State) -> None:
    state.state['from_test_2'] = 2
    assert state.state['from_fixture'] == 0
    assert state.state['from_test_1'] == 1
    assert state.state['from_test_2'] == 2

, (, , ). , module (scope=function , .

, , .

- ( , 1 2 ). .

+1

, , , . , , , .

, , , .

class mylib:
    @classmethod
    def get_a(cls):
        return 'a'

    @classmethod
    def convert_a_to_b(cls, a):
        return 'b'

    @classmethod
    def works_with(cls, a, b):
        return True

class TestMyStuff(object):
    def test_first(self):
        self.__class__.a = mylib.get_a()

    def test_conversion(self):
        self.__class__.b = mylib.convert_a_to_b(self.a)

    def test_a_works_with_b(self):
        mylib.works_with(self.a, self.b)

The advantage of this approach is that it stores the state enclosed in the test class (there are no auxiliary functions that must be present to run the test), and it would be inconvenient for another class to expect the TestMyStuff state that will be present when a different class is launched.

I think that each of these approaches discussed has its merits and intends to use each approach in which it is best suited.

0
source

Source: https://habr.com/ru/post/1752372/


All Articles