python pytest 参数化的几种方式

发布时间 2023-07-03 15:24:59作者: 云淡#风清

在pytest框架中,可以使用多种方式进行参数化测试。以下是一些常见的参数化方式及其示例:

  1. 使用@pytest.mark.parametrize装饰器:可以使用pytest提供的@pytest.mark.parametrize装饰器来指定参数化测试的参数。下面是一个示例:
    import pytest
    
    @pytest.mark.parametrize("num, expected", [
        (1, 1),
        (2, 4),
        (3, 9)
    ])
    def test_square(num, expected):
        assert num ** 2 == expected

    在上面的示例中,通过给@pytest.mark.parametrize装饰器传递参数列表,每个参数列表都是一个参数化测试的参数组合。每个参数组合都会作为单独的测试用例执行。

  2. 使用pytest.fixture装饰器:可以使用pytest.fixture装饰器创建一个可以在测试函数中使用的参数化fixture。下面是一个示例:
    import pytest
    
    @pytest.fixture(params=[1, 2, 3])
    def num(request):
        return request.param
    
    def test_square(num):
        assert num ** 2 == num * num

    在上面的示例中,使用@pytest.fixture装饰器创建了一个名为num的参数化fixture。通过在测试函数的参数中引用该fixture,每个参数组合都会作为单独的测试用例执行。

  3. 使用pytest_generate_tests钩子函数:可以使用pytest的钩子函数pytest_generate_tests来自定义参数化测试的生成方式。下面是一个示例:
    import pytest
    
    def pytest_generate_tests(metafunc):
        if 'num' in metafunc.fixturenames:
            metafunc.parametrize('num', [1, 2, 3])
    
    def test_square(num):
        assert num ** 2 == num * num

    在上面的示例中,定义了一个pytest_generate_tests钩子函数,通过判断测试函数的参数是否存在来进行参数化。每个参数组合都会作为单独的测试用例执行。

  4. 使用pytest-data库:pytest-data是一个用于参数化测试的扩展库,可以通过加载外部数据文件来提供参数化测试的数据。以下是一个示例:

    import pytest
    from pytest_data import data
    
    @pytest.mark.datafiles('test_data.csv')
    def test_addition(datafiles):
        data_file = datafiles / 'test_data.csv'
        for row in data(data_file):
            num1 = row['num1']
            num2 = row['num2']
            expected = row['expected']
            assert num1 + num2 == expected

    在上面的示例中,使用pytest-data库的data装饰器加载了一个CSV文件作为测试数据,并在测试函数中使用了这些数据进行参数化测试。

  5. 使用CSV或Excel文件:如果希望使用CSV或Excel文件作为测试数据进行参数化,可以使用Python的csv或openpyxl库来读取文件并生成参数组合。以下是一个示例:
    import pytest
    import csv
    
    def read_csv(file_path):
        with open(file_path, 'r') as csv_file:
            csv_reader = csv.DictReader(csv_file)
            for row in csv_reader:
                yield row
    
    @pytest.mark.parametrize("data", read_csv("test_data.csv"))
    def test_multiply(data):
        num1 = int(data['num1'])
        num2 = int(data['num2'])
        expected = int(data['expected'])
        assert num1 * num2 == expected

    在上面的示例中,通过read_csv函数读取CSV文件的每一行作为参数组合,并使用@pytest.mark.parametrize装饰器进行参数化测试。

  6. 使用pytest.mark.parametrize装饰器嵌套:可以使用pytest.mark.parametrize装饰器嵌套来进行多个参数的组合。示例如下:
    import pytest
    
    @pytest.mark.parametrize("num", [1, 2])
    @pytest.mark.parametrize("operation", ["add", "subtract"])
    def test_calculator(num, operation):
        if operation == "add":
            result = num + num
            assert result == 2 * num
        elif operation == "subtract":
            result = num - num
            assert result == 0

    在上面的示例中,使用了两个参数化装饰器,分别对num和operation进行参数化。每个参数化装饰器中的参数都会进行组合,生成不同的测试用例。

  7. 使用自定义参数化装饰器:除了pytest提供的装饰器,还可以自定义参数化装饰器来实现特定的参数化方式。示例如下
    import pytest
    
    def custom_parametrize(*args):
        def decorator(func):
            for arg in args:
                func = pytest.mark.parametrize(*arg)(func)
            return func
        return decorator
    
    @custom_parametrize(
        ("num", [1, 2, 3]),
        ("operation", ["add", "subtract"])
    )
    def test_calculator(num, operation):
        if operation == "add":
            result = num + num
            assert result == 2 * num
        elif operation == "subtract":
            result = num - num
            assert result == 0

    在上面的示例中,定义了一个自定义的参数化装饰器custom_parametrize,接受一系列参数化参数,并将其应用于测试函数。使用自定义装饰器可以实现更复杂的参数化逻辑。