Параметризация тестовой функции pytest на основе вывода setup_module или другой функции динамически

#python #testing #pytest

#python #тестирование #pytest

Вопрос:

У меня есть код pytest в У меня есть setup_module, в котором я выполняю некоторую обработку кода, которая изменяет список списков с именем testdata, который объявлен глобально. Мне нужно динамически передавать этот список списков в мой тестовый пример на основе того, что я получаю от setup_module.

 testdata = [['servername_1', 'servermac_1', 'vlans'],['servername_2', 'servermac_2', 'vlans']]
 
def setup_module(module):
    #global testdata
    #do some steps
    #based on if the server has issues or server mac is different, 
    # return testdata which may or may not remove one or both list from test data(modified testdata)

def teardown_module(module):
    #close ssh connection

@pytest.mark.parametrize('servername, servermac, vlan', testdata)
def test_function(servername, servermac, vlans):
    for vlans in vlans:
       do ssh to servername:
          #do things
  

В любом случае для динамической параметризации тестовых данных в test_function.

Я пробовал :

a) С текущим кодом, даже если setup_module удаляет один список из тестовых данных, поскольку мой тестовый пример параметризуется с помощью testdata глобально, который имеет два списка, тестовые примеры выполняются дважды для одного списка в testdata. Я читал из других вопросов, что это невозможно в соответствии со структурой pytest.

б) Если я попробую приспособление, выполнив что-то вроде :

 testdata = [['servername_1', 'servermac_1', 'vlans'],['servername_2', 'servermac_2', 'vlans']]

@pytest.fixture
def setup():
    #do some steps
    #based on if the server has issues or server mac is different, 
    # return testdata which may or may not remove one or both list from test data

def teardown_module(module):
    #close ssh connection


def test_function(setup):
    testdata = setup 

    for test in testdata:
        servername = test[0]
        servermac = test[1]
        vlans = test[2]

    for vlans in vlans:
       do ssh to servername:
          #do things
  

При такой структуре кода pytest не учитывает, что это было два набора тестовых примеров, а только один набор случаев. Кроме того, я не могу использовать assert здесь, поскольку, если что-то не удается для 1-го имени сервера, и если я утверждаю, что оно равно false, код вообще не будет выполняться для 2-го имени сервера.

Может кто-нибудь, пожалуйста, подсказать, делаю ли я здесь что-то не так. Приносим извинения, если не следовали рекомендациям по вопросам, поскольку здесь впервые задается вопрос.

Комментарии:

1. Известна ли необходимая информация во setup_module время загрузки или только позже? В первом случае вы могли бы просто вызвать функцию в своем модуле напрямую.

2. Set up имеет множество вызовов API, которые запускаются после запуска запуска. Я попытался вызвать setup_module или другую функцию, но у меня это не сработало. Он идентифицировал 3 тестовых примера вместо 2.

3. Я добавил ответ для этого случая, пожалуйста, проверьте, работает ли он для вас.

4. Спасибо за ответ. Я попробовал код, который вы мне дали. Это работает для меня, но отчасти частично. Причина, по которой я говорю это, заключается в том, что она предоставляет мне тестовые функции, как вы предложили, но когда я изменил свою переменную testdata в параметре setup_testdata(), это изменение не было отражено в параметризации. Он принимал только значение переменной testdata, объявленное глобально. Кроме того, если в setup_testdata(), если я изменяю тестовые данные, удаляя vlan и какой-либо другой параметр, он все равно показывает vlan, что означает, что изменения не отражаются в параметризации. Я делаю что-то не так, ожидая этого

5. Извините, мой плохой — вы правы, это не работает, потому setup_testdata что вызывается слишком поздно. Обновит ответ…

Ответ №1:

Если вы не знаете тестовые наборы во время загрузки, вы можете параметризовать свою функцию во pytest_generate_tests время выполнения. Чтобы иметь возможность устанавливать тестовые данные до этого, вы должны использовать перехват инициализации, который выполняется раньше pytest_generate_tests , например pytest_configure (который должен быть помещен в a conftest.py ). Вот возможная реализация:

conftest.py

 def pytest_configure(config):
    # save the testdata in the config, so you can access it from the hook
    config.testdata = calculate_testdata()
  

test.py

 def teardown_module(module):
    # close ssh connection

@pytest.hookimpl
def pytest_generate_tests(metafunc):
    if all([name in metafunc.fixturenames
            for name in ("servername", "servermac", "vlans")]):
        metafunc.parametrize(("servername", "servermac", "vlans"), 
                             metafunc.config.testdata)

def test_function(servername, servermac, vlans):
    ...
  

В случае вашего примера testdata это приведет к созданию тестовых функций:

 test.py::test_function[servername_1-servermac_1-vlans] 
test.py::test_function[servername_2-servermac_2-vlans]