0

我将 testinfra 与 ansible 传输一起使用。它提供了host具有的夹具ansible,所以我可以做到host.ansible.get_variables()

现在我需要根据该库存中的值创建测试的参数化。

存货:

foo:
  hosts:
    foo1:
      somedata:
        - data1
        - data2

我想编写一个测试,测试清单中每个主机的 somedata 中的每个“数据”。“每个主机”部分由 testnfra 处理,但我正在努力进行测试的参数化:

@pytest.fixture
def somedata(host):
    return host.ansible.get_variables()["somedata"]

@pytest.fixture(params=somedata):
def data(request):
    return request.param


def test_data(host, data):
   assert 'data' in data

我尝试了两种方式:

  • @pytest.fixture(params=somedata)->TypeError: 'function' object is not iterable
  • @pytest.fixture(params=somedata())->Fixture "somedata" called directly. Fixtures are not meant to be called directly...

我怎样才能做到这一点?我知道我不能在测试时更改测试次数,但我很确定我在收集时有相同的库存,所以,理论上,它是可行的......

4

2 回答 2

0

您应该使用辅助函数而不是夹具来参数化另一个夹具。Fixtures 不能用作 pytest 中的装饰器参数。

def somedata(host):
    return host.ansible.get_variables()["somedata"]

@pytest.fixture(params=somedata()):
def data(request):
    return request.param


def test_data(host, data):
   assert 'data' in data

这假设主机不是固定装置。

如果主机是固定装置,则有一种解决问题的方法。您应该将参数写入 tmp 文件或环境变量中,并使用辅助函数读取它。

import os

@pytest.fixture(autouse=True)
def somedata(host):
    os.environ["host_param"] = host.ansible.get_variables()["somedata"]

def get_params():
    return os.environ["host_param"] # do some clean up to return a list instead of a string    


@pytest.fixture(params=get_params()):
def data(request):
    return request.param


def test_data(host, data):
   assert 'data' in data
于 2019-08-27T12:54:53.903 回答
0

在阅读了大量源代码后,我得出结论,在收集时调用固定装置是不可能的。收集时没有固定装置,任何参数化都应该在调用任何测试之前进行。此外,在测试时更改测试数量是不可能的(因此没有夹具可以改变它)。

回答我自己关于使用 Ansible 库存参数化测试函数的问题:这是可能的,但它需要手动读取库存、主机等。为此有一个特殊的钩子:(pytest_generate_tests它是一个函数,而不是固定装置)。

host_interface我目前通过夹具获取任何测试参数的代码是:

def cartesian(hosts, ar): 
    for host in hosts:
        for interface in ar.get_variables(host).get("interfaces",[]):
            yield (host, interface)

def pytest_generate_tests(metafunc):
    if 'host_interface' in metafunc.fixturenames:
        inventory_file = metafunc.config.getoption('ansible_inventory')
        ansible_config = testinfra.utils.ansible_runner.get_ansible_config()
        inventory = testinfra.utils.ansible_runner.get_ansible_inventory(ansible_config, inventory_file)
        ar = testinfra.utils.ansible_runner.AnsibleRunner(inventory_file)
        hosts = ar.get_hosts(metafunc.config.option.hosts)
        metafunc.parametrize("host_interface", cartesian(hosts, ar))
于 2019-08-27T13:44:03.380 回答