【pytest】paramtrize 参数化、数据驱动

本文深入讲解pytest中的参数化功能,包括单参数、多参数及多次使用参数化的具体应用,通过实例展示如何有效利用参数化提高测试效率。

paramtrize 参数化:

pytest 中可以使用 @pytest.mak.paramtrize(argsnames, argsvalues, ids=None) 来实现参数化;

主要参数说明:

  • argsnames :参数名,是个字符串,如中间用逗号分隔则表示为多个参数名;
  • argsvalues :参数值,参数组成的列表,列表中有几个元素,就会生成几条测试用例;

使用方法:

  1. 使用 @pytest.mak.paramtrize() 装饰测试方法;
  2. parametrize('data', param) 中的 ‘data’ 是自定义的参数名,param 是引入的参数列表;
  3. 将自定义的参数名 data 作为参数传给测试用例 test_func;
  4. 然后就可以在测试用例内部使用 data 的参数了;

整个过程中,pytest 将参数列表 [1, 2, 3] 中的 3 个元素取出来,用每个元素生成 1 条测试用例,并且将元素赋值给 data 作为测试用例的参数,由测试用例自由使用;

# test_moduleName.py

import pytest

class TestClass_1:
    """测试类1"""

    param = [1, 2, 3]
    
    # 'data' :自定义的参数名
    # param  :参数列表
    @pytest.mark.parametrize('data', param)
    def test_func(self, data):  # 将参数名作为测试方法的参数
        """测试方法"""

        print('\n参数:', data)  # 实际得到的参数
# 执行结果:
============================= test session starts =============================
test_moduleName.py::TestClass_1::test_func[1] 
参数:data =  1
PASSED
test_moduleName.py::TestClass_1::test_func[2] 
参数:data =  2
PASSED
test_moduleName.py::TestClass_1::test_func[3] 
参数:data =  3
PASSED

============================== 3 passed in 0.03s ==============================

Process finished with exit code 0

多个参数名的用法:

前面讲了参数名可以就用逗号分隔,表示为多个参数名,当使用多个参数名时要注意,参数列表中的元素必须是可拆包的数组,并且数组内的元素数必须和参数名的数量相同;

# test_moduleName.py

import pytest


class TestClass_1:
    """测试类1"""

    param = [('admin1', 'pwd001'), ('admin2', 'pwd002'), ('admin3', 'pwd003')]
    # 因为参数名是 2 个,所以列表的每个元素都必须是长度为 2 的数组;
    @pytest.mark.parametrize('uname, pwd', param)
    def test_func(self, uname, pwd):
        """测试方法"""

        print('\n参数:uname = ', uname)
        print('参数:pwd = ', pwd)
# 执行结果
============================= test session starts =============================
test_moduleName.py::TestClass_1::test_func[admin1-pwd001] 
参数:uname =  admin1
参数:pwd =  pwd001
PASSED
test_moduleName.py::TestClass_1::test_func[admin2-pwd002] 
参数:uname =  admin2
参数:pwd =  pwd002
PASSED
test_moduleName.py::TestClass_1::test_func[admin3-pwd003] 
参数:uname =  admin3
参数:pwd =  pwd003
PASSED

============================== 3 passed in 0.02s ==============================

多次使用 paramtrize :

同一个测试用例还可以同时适用多个 @pytest.mak.paramtrize(),多个 paramtrize 的所有元素互相组合(类似笛卡儿乘积)生成大量测试用例;

# test_moduleName.py

import pytest


class TestClass_1:
    """测试类1"""

    @pytest.mark.parametrize('date3', ['value3-1', 'value3-2', 'value3-3'])
    @pytest.mark.parametrize('date2', ['value2-1', 'value2-2', 'value2-3'])
    @pytest.mark.parametrize('date1', ['value1-1', 'value1-2', 'value1-3'])
    def test_func(self, date1, date2, date3):
        """测试方法"""

        print('\n参数:date1 = ', date1)
        print('参数:date2 = ', date2)
        print('参数:date3 = ', date3)

如下所示,3 个 paramtrize() ,共有 3 * 3 * 3 = 27 种组合,pytest 便会生成 27 条测试用例!

test_moduleName.py::TestClass_1::test_func[value1.1-value2.1-value3.1] 
test_moduleName.py::TestClass_1::test_func[value1.1-value2.1-value3.2] 
test_moduleName.py::TestClass_1::test_func[value1.1-value2.1-value3.3] 
test_moduleName.py::TestClass_1::test_func[value1.1-value2.2-value3.1] 
test_moduleName.py::TestClass_1::test_func[value1.1-value2.2-value3.2] 
test_moduleName.py::TestClass_1::test_func[value1.1-value2.2-value3.3] 
test_moduleName.py::TestClass_1::test_func[value1.1-value2.3-value3.1] 
test_moduleName.py::TestClass_1::test_func[value1.1-value2.3-value3.2] 
test_moduleName.py::TestClass_1::test_func[value1.1-value2.3-value3.3] 
test_moduleName.py::TestClass_1::test_func[value1.2-value2.1-value3.1] 
test_moduleName.py::TestClass_1::test_func[value1.2-value2.1-value3.2] 
test_moduleName.py::TestClass_1::test_func[value1.2-value2.1-value3.3] 
test_moduleName.py::TestClass_1::test_func[value1.2-value2.2-value3.1] 
test_moduleName.py::TestClass_1::test_func[value1.2-value2.2-value3.2] 
test_moduleName.py::TestClass_1::test_func[value1.2-value2.2-value3.3] 
test_moduleName.py::TestClass_1::test_func[value1.2-value2.3-value3.1] 
test_moduleName.py::TestClass_1::test_func[value1.2-value2.3-value3.2] 
test_moduleName.py::TestClass_1::test_func[value1.2-value2.3-value3.3] 
test_moduleName.py::TestClass_1::test_func[value1.3-value2.1-value3.1] 
test_moduleName.py::TestClass_1::test_func[value1.3-value2.1-value3.2] 
test_moduleName.py::TestClass_1::test_func[value1.3-value2.1-value3.3] 
test_moduleName.py::TestClass_1::test_func[value1.3-value2.2-value3.1] 
test_moduleName.py::TestClass_1::test_func[value1.3-value2.2-value3.2] 
test_moduleName.py::TestClass_1::test_func[value1.3-value2.2-value3.3] 
test_moduleName.py::TestClass_1::test_func[value1.3-value2.3-value3.1] 
test_moduleName.py::TestClass_1::test_func[value1.3-value2.3-value3.2] 
test_moduleName.py::TestClass_1::test_func[value1.3-value2.3-value3.3] 

 

<think>好的,用户想了解如何在pytest中实现参数化数据驱动测试,需要示和教程。首先,我需要回忆pytest参数化方法,记得是使用@pytest.mark.parametrize装饰器。根据用户提供的引用资料,特别是引用[2]和[3],可以确认这一点。 接下来,用户可能需要一个简单的示来理解基本用法。比如,测试一个加法函数,参数化不同的输入和期望结果。应该分步骤说明如何导入模块、编写测试用和应用装饰器。注意代码块要正确,语法无误。 然后,可能需要展示多个参数的情况,比如同时参数化a和b以及预期结果。引用[3]提到测试方法中可以直接使用参数化的参数,所以需要展示这一点。此外,用户可能想知道如何处理多个参数组合,比如使用列表嵌套元组的结构。 用户还可能对数据来源感兴趣,比如从外部文件如Excel或YAML读取数据。根据引用[4],可以提到如何从Excel读取数据,但可能需要给出具体代码示,比如使用pandas库读取Excel文件,然后将数据转换为参数化的格式。 另外,需要提醒用户注意参数化装饰器的参数名称要与测试函数的参数对应,否则会出错。同时,强调参数化可以多次使用,覆盖多种测试场景,提升测试覆盖率。 最后,总结参数化的优势,比如减少重复代码,便于维护,以及结合外部文件实现数据驱动。可能还要指出常见错误,比如数据格式不正确或路径问题,帮助用户避免踩坑。 检查是否覆盖了用户的问题:参数化、多个参数、外部数据源。确保回答结构清晰,分步骤说明,并引用提供的资料。代码示要正确,用中文解释每个部分的作用。这样用户应该能理解如何在pytest中实现数据驱动的测试了。</think>### 如何在 pytest 中实现参数化数据驱动测试? #### 1. 参数化基础:使用 `@pytest.mark.parametrize` pytest 通过装饰器 `@pytest.mark.parametrize` 实现参数化。以下是**单个参数**的示: ```python import pytest # 定义被测试的加法函数 def my_add(a, b): return a + b # 参数化测试用 @pytest.mark.parametrize("a, b, expected", [(1, 2, 3), (0, 0, 0), (-1, 1, 0)]) def test_add(a, b, expected): assert my_add(a, b) == expected # 断言结果是否符合预期 ``` - **关键点**: - 装饰器第一个参数是字符串 `"a, b, expected"`,表示测试函数的参数名; - 第二个参数是数据列表 `[(1,2,3), ...]`,每组数据对应一次测试执行[^3]。 #### 2. 多参数组合与复杂场景 若需要测试**多组参数组合**,可以扩展数据列表: ```python @pytest.mark.parametrize("input_a, input_b, expected", [ (5, 3, 8), # 正整数相加 (2.5, 1.5, 4.0), # 浮点数相加 ("hello", " world", "hello world") # 字符串拼接 ]) def test_multiple_types(input_a, input_b, expected): assert my_add(input_a, input_b) == expected ``` #### 3. 从外部文件读取测试数据(如 Excel) 结合 `pandas` 库实现 Excel 数据驱动: ```python import pandas as pd # 从 Excel 读取数据(假设文件 test_data.xlsx 中有列 a, b, expected) def read_excel_data(): df = pd.read_excel("test_data.xlsx") return [tuple(row) for row in df.values] @pytest.mark.parametrize("a, b, expected", read_excel_data()) def test_excel_data(a, b, expected): assert my_add(a, b) == expected ``` - **注意**:需安装 `pandas` 和 `openpyxl` 库:`pip install pandas openpyxl`[^4]。 #### 4. 参数化与其他装饰器结合 可同时使用 `@pytest.mark.skip` 或自定义标记: ```python @pytest.mark.slow # 自定义标记 @pytest.mark.parametrize("a, b, expected", [(100, 200, 300)]) def test_large_numbers(a, b, expected): assert my_add(a, b) == expected ``` #### 5. 常见问题与解决 - **错误提示**:`ParameterSet` 格式错误 确保数据列表中的每组数据长度与参数数量一致。 - **动态生成参数**: 可在函数中生成参数列表,再传递给装饰器: ```python def generate_data(): return [(x, x, x*2) for x in range(3)] @pytest.mark.parametrize("a, b, expected", generate_data()) def test_dynamic_data(a, b, expected): assert my_add(a, b) == expected ``` ### 总结 - **核心方法**:`@pytest.mark.parametrize` 装饰器 + 数据列表; - **优势**:减少重复代码,支持复杂数据源(Excel/YAML/JSON); - **典型应用**:接口测试、边界值测试、多输入组合验证[^2]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值