如何创建依赖于另一个参数化灯具的值的参数化灯具?

时间:2020-07-23 21:59:26

标签: python pytest

示例:

from pytest import fixture, skip

@fixture(params=['a', 'b'])
def f1(request):
    yield request.param


params = [('a', 1), ('a', 2), ('b', 10), ('b', 20)]
@fixture(params=params, ids=[str(x) for x in params])
def f2(f1, request):
    if request.param[0] == f1:
        yield request.param[1]
    else:
        skip('invalid')

def test_foo(f1, f2):
    return

这是一个“基础”装置f1。然后“堆叠”的夹具f2应该为(1, 2)产生值f1='a'和为(10, 20)产生值f1='b'

给予:

a.py::test_foo[a-('a', 1)] PASSED
a.py::test_foo[a-('a', 2)] PASSED
a.py::test_foo[a-('b', 10)] SKIPPED
a.py::test_foo[a-('b', 20)] SKIPPED
a.py::test_foo[b-('a', 1)] SKIPPED
a.py::test_foo[b-('a', 2)] SKIPPED
a.py::test_foo[b-('b', 10)] PASSED
a.py::test_foo[b-('b', 20)] PASSED

这与我想要达到的目标很接近,除了我想对此进行改进

  • SKIPPED变体根本不会显示为测试用例
  • 已设置参数的测试用例id无需重复f1固定装置即可显示。理想情况下,像<f1-value><separator><f2-value>之类的a-2b-10之类的
  • 以某种更明智的方式进行理想的定义,而无需重复

替代方法1:参数化解决方法

有一种使用参数化的解决方法:

@pytest.mark.parametrize(params=('f1,f2', (('a', 1), ('b', 10))))
def test_foo():
    return

但是,这并不是真正的解决方案,因为它仅适用于相对简单和隔离的设置。发生故障的地方是在许多测试案例中使用了基本夹具f1时,还有其他夹具f1_n堆积在f1上方,仅像:

@fixture
def f1_1(f1):
    return

在这一点上,使用参数化解决方法会导致重复并损害其他堆叠式夹具的重用性。

替代2:pytest_generate_tests

https://docs.pytest.org/en/latest/parametrize.html

f2_vals = {'a': (1,2), 'b': (10,20)}

def pytest_generate_tests(metafunc):
    if "f2" in metafunc.fixturenames:
        assert "f1" in metafunc.fixturenames
        metafunc.parametrize("f2", f2_vals[get_f1_val()])

但是我看不到如何实现get_f1_val,并且对此方法几乎没有信心,因为pytest似乎是在先收集测试用例然后执行它们的阶段中运行。

替代3:测试用例忽略/选择

目前https://github.com/pytest-dev/pytest/issues/3730处有功能请求,但仅解决了从测试会话结果中删除无效的测试用例组合的部分。

1 个答案:

答案 0 :(得分:0)

您的替代方法2的进一步努力:

d = a * A.getX() + b * A.getY() + c * A.getZ();