Добавить фикстуры PyTest в тестовый класс с помощью внедрения зависимостей - PullRequest
2 голосов
/ 07 августа 2020

Я использую Python 3 с PyTest и определил несколько объектов фикстуры в conftest.py. Проблема, с которой я столкнулся, заключается в том, что есть некоторые объекты фикстур, которые потребуются для каждого теста. Запрос этих ссылок на приспособления во всех тестовых примерах приводит к многократному повторению стандартного кода.

Вот приспособление в conftest.py:

def fixtureA(request):
    _fixture = FixtureA()
    # initialize the fixture, do stuff with request
    return _fixture

Вот текущий тестовый класс, в котором я хочу удалите все приспособления из аргументов для удобочитаемости:

class TestSomeFeature(BaseTest):

    def test_some_function(self, fixtureA, fixtureB, fixtureC):
        fixtureA.doSomething()
        # execute test case, do stuff with other fixtures     

    def test_some_other_function(self, fixtureA, fixtureB, fixtureC):
        data = fixtureB.getData()
        # execute test case

Этот подход работает, но я хотел бы найти способ использовать инъекцию зависимостей (или аналогичный), чтобы автоматически вводить фикстуры в атрибуты BaseTest без чтобы указать их в списке аргументов каждого тестового примера. Я ищу что-то подобное, но открыт для любых других предложений:

class BaseTest:
    # Can constructor arguments be injected using DI framework?
    # hint: answer is no!
    def __init__(fixtureA, fixtureB, fixtureC):
        self.fixtureA = fixtureA
        self.fixtureB = fixtureB
        self.fixtureC = fixtureC

Я хочу, чтобы тестовый класс выглядел так, намного чище!

class TestSomeFeature(BaseTest):

    def test_some_function(self):
        self.FixtureA.doSomething()
        # execute test case

    def test_some_other_function(self):
        data = self.FixtureB.getData()
        # execute test case

Ответы [ 2 ]

2 голосов
/ 07 августа 2020

Во-первых, вы можете определять фикстуры как в conftest.py, так и в тестовых классах. Разница в видимости: если вы определяете прибор в conftest.py, он виден всем тестам на уровне этого conftest.py файла и ниже. Если вы определяете его внутри тестового модуля, он виден только в этом модуле. Если вы определяете его внутри тестового класса, он виден в этом классе и производных классах.

Также обратите внимание, что вы можете использовать autotest=True также, если вы возвращаете значение - вам просто нужно сослаться на фикстуру в соответствующие тесты. Вы также можете сохранить значение прибора в переменной. Вот упрощенный пример c для обоих случаев, если вы используете базовый класс:

class TestBase:
    @pytest.fixture(autouse=True)
    def fixture1(self):
        self.value1 = 1  # save the fixture value
        yield

    @pytest.fixture
    def fixture2(self):
        yield 2  # return the fixture value - fixtue has to be referenced
        # autouse can still make sense if there is setup/tearDown code,
        # and the fixture must not be referenced in all of the tests

    @pytest.fixture(autouse=True)
    def fixture3(self):
        self.value3 = 3
        yield 3  # do both - can be used either way


class TestDerived(TestBase):
    def test_1(self):
        assert self.value1 == 1

    def test_2(self, fixture2):
        assert fixture2 == 2

    def test_3_1(self):
        assert self.value3 == 3

    def test_3_2(self, fixture3):
        assert fixture3 == 3

Обратите внимание, что вы получаете значение прибора , а не сам прибор, если вы ссылаются на прибор, поэтому нет необходимости (и это невозможно) вызывать прибор - вместо этого вы напрямую используете значение, возвращаемое прибором.

1 голос
/ 16 августа 2020

Я использовал следующий код, основанный на ответе от @ MrBeanBremen.

Я создал фикстуру с именем injector в моем базовом классе, единственная ответственность которой - вводить фикстуры из conftest в базовый класс :

class BaseTest:
    @fixture(autouse=True)
    def injector(self, fixtureA, fixtureB):
        self.fixtureA = fixtureA
        self.fixtureB = fixtureB

Все тестовые классы, унаследованные от BaseTest, теперь могут обращаться к фикстурам без какого-либо стандартного кода. Обратите внимание, что вы не можете добавить конструктор в BaseTest, поскольку PyTest полностью проигнорирует тестовый класс, если вы это сделаете. Ваша IDE может генерировать предупреждение, которое вы можете подавить в настройках.

...