如何通过pytest对参数的笛卡尔乘积进行参数化(某些固定)?

时间:2019-04-28 20:49:23

标签: python unit-testing pytest

我正在为基类及其子类编写测试。 大致如下:

@pytest.fixture()
def bc()
    return BaseClass(...)

@pytest.mark.parametrize('param1,param2', [...])
def test_baseclass_func1(bc, param1, param2):
    assert ...

@pytest.mark.parametrize('param1,param2', [...])
def test_baseclass_func2(bc, param1, param2):
    assert ...

@pytest.mark.parametrize('param1,param2', [xyz])
def test_baseclass_func3(bc, param1, param2):
    assert ...

@pytest.mark.parametrize('param1,param2', [xyz])
def test_subclass1_func3(param1, param2):
    sc1 = SubClass1(...)
    assert ...

@pytest.mark.parametrize('param1,param2', [xyz])
def test_subclass2_func3(param1, param2):
    sc1 = SubClass2(...)
    assert ...

因此,我希望使用固定的BaseClass实例,没有明显的理由在子类上使用Fixture,并且希望避免对func3进行3次测试复制粘贴。
我最好的选择是再使用一个参数化:

@pytest.mark.parametrize('classtype', [
        (BaseClass,),
        (SubClass1,),
        (SubClass2,),
])
@pytest.mark.parametrize('param1,param2', [xyz])
def test_func3(classtype, param1, param2):
    class_inst = classtype()
    assert ...

但是由于它需要一个额外的BaseClass实例,我想有一个更好的解决方案。我想念什么技巧?

2 个答案:

答案 0 :(得分:2)

如果我理解正确,则可以使用indirect parametrization将类参数转换为传递给测试的实例:

List<String> allIds = Stream.of(
    person.baseballPlayers.stream().map(BaseballPlayer::getId),
    person.mmaFighters.stream().map(MmaFighter::getId),
    person.rugbyPlayers.stream().map(RugbyPlayer::getId))
    .flatMap(Function.identity())
    .collect(Collectors.toList());

由于@pytest.fixture(scope='session') def instance(request): cls = request.param instance = cls() yield instance # cleanup instance here if necessary @pytest.mark.parametrize('instance', (BaseClass, SubClass1, SubClass2,), indirect=True) @pytest.mark.parametrize('param1,param2', (('spam', 'foo'), ('eggs', 'bar'))) def test_func3(instance, param1, param2): assert instance.func3(param1, param2) == 'bacon' 固定装置是会话范围的,因此所有创建的实例都将创建一次并在整个测试会话中重复使用。如果您需要更复杂的实例创建,则可以在灯具中进行,以保持测试的清洁。重复使用instance固定装置的示例:

bc

答案 1 :(得分:1)

也许您对这样的治具感兴趣,该治具在不被调用之前不会创建BaseClass实例:

@pytest.fixture
def callable_bc():
    def _bc():
        return BaseClass(...)
    return _bc

@pytest.mark.parametrize('classtype', [
        (BaseClass,),
        (SubClass1,),
        (SubClass2,),
])
@pytest.mark.parametrize('param1,param2', [xyz])
def test_func3(classtype, param1, param2, callable_bc):
    class_inst = classtype() if classtype != BaseClass else callable_bc()
    assert ...