【问题标题】:Indirect parameterization with multiple parametrize decorators in pytest在 pytest 中使用多个参数化装饰器进行间接参数化
【发布时间】:2022-11-12 09:24:30
【问题描述】:

首先,如果我做错了,请提前抱歉,这是我在stackoverflow上提出的第一个问题。所以请让我知道我的配方是否无效。

所以我正在做一个项目,我想对一个管道进行单元测试,该管道根据用户选择的参数以模块化方式调用多个函数。我对这个单元测试的目标是检查用户可以给出的所有可能的组合是否按预期工作。

所以我所拥有的是某些进程拥有并且我想使用的所有选项的列表@pytest.mark.parametrize() 迭代它们并创建所有可能的组合。

因为使用这些参数创建了一个对象,并且我想将此设置用于多个测试函数,所以我想构建一个夹具,它采用这些参数(间接)并返回应该在测试函数中使用的对象。

这甚至可以通过间接参数化实现吗?

简化的设置如下所示:

PARAMETER1_LIST = ["option 1", "option 2", "option 3"]
PARAMETER2_LIST = ["value 1", "value 2"]

@pytest.fixture
def test_pipeline_class(request):
    pipeline_parameters = []
    for parameter in request.param:
        pipeline_parameters.append(parameter)
    test_pipeline = PipelineClass(pipeline_parameters)
    return test_pipeline


@pytest.mark.parametrize("parameter1", PARAMETER1_LIST, indirect=True)
@pytest.mark.parametrize("parameter2", PARAMETER2_LIST, indirect=True)
def test_pipeline_combinations(parameter1, parameter2, test_pipeline_class):
    print(test_pipeline_class.parameters)
    # Further tests

我很确定我的代码有很多问题(例如对request.param 的迭代),但我想知道这是否可能,或者是否有另一种方法可以以更清洁的方式进行。

【问题讨论】:

    标签: python pytest parameterized-unit-test


    【解决方案1】:

    这将像这样工作:

    import pytest
    
    
    PARAMETER1_LIST = ["option 1", "option 2", "option 3"]
    PARAMETER2_LIST = ["value 1", "value 2"]
    
    
    class PipelineClass:
        def __init__(self, pipeline_parameters):
            self.parameters = pipeline_parameters
    
    @pytest.fixture
    def pipeline_class(request):  # This name can not start with test as pytest tries to run it as a test 
        pipeline_parameters = []
        for parameter in request.param:
            pipeline_parameters.append(parameter)
        test_pipeline = PipelineClass(pipeline_parameters)
        return test_pipeline
    
    
    # Parameter name should be == fixture name, so you can make this parametrize only once for one fixture for one test
    # Parameters should be passed in [] as the parametrize method waits an iterable as the second argument. 
    # And then it's handled as if it is not in []
    # So this feature is created to use the same fixture but with different parameters for different tests.
    @pytest.mark.parametrize("pipeline_class", [PARAMETER1_LIST], indirect=True)  
    def test_pipeline_combinations(pipeline_class):  
        print(pipeline_class.parameters)
    
    
    @pytest.mark.parametrize("pipeline_class", [PARAMETER2_LIST], indirect=True)
    def test_pipeline_combinations2(pipeline_class):
        print(pipeline_class.parameters)
    

    在代码 cmets 中,我添加了关于我所做更改的解释。
    所以,基本上,你不能在一次测试中使用一个夹具两次。

    如果您想使用以下两个列表的组合运行测试 6 次:“选项 1”+“值 1”、“选项 1”+“值 2”、“选项 1”+“值 3”、“选项 2” " + "value 1", "option 2" + "value 2", "option 2" + "value 3" 你可以这样做:

    import pytest
    
    
    PARAMETER1_LIST = ["option 1", "option 2", "option 3"]
    PARAMETER2_LIST = ["value 1", "value 2"]
    
    
    class PipelineClass:
        def __init__(self, pipeline_parameters):
            self.parameters = pipeline_parameters
    
    
    @pytest.fixture(scope='function')
    def pipeline_class(request):
        return PipelineClass(request.param)
    
    
    def joined_params():
        for opt in PARAMETER1_LIST:
            for val in PARAMETER2_LIST:
                yield opt, val
    
    
    @pytest.mark.parametrize('pipeline_class', joined_params(), indirect=True)
    def test_pipeline_combinations(pipeline_class):
        print(pipeline_class.parameters)
    
    

    【讨论】:

    • 感谢您的回答,它已经帮助我更多地掌握 pytest。剩下的唯一问题是我没有使用您的解决方案获得参数组合, - 我可能对此不够清楚。考虑到给定的示例,我想运行测试 6 次,其中两个列表的组合:“选项 1”+“值 1”、“选项 1”+“值 2”、“选项 1”+“值 3”, “选项 2”+“值 1”、“选项 2”+“值 2”、“选项 2”+“值 3”
    • 我在答案中添加了如何做你想做的事。
    猜你喜欢
    • 2019-11-11
    • 1970-01-01
    • 2021-07-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-02-21
    • 2023-02-15
    • 1970-01-01
    相关资源
    最近更新 更多