【pytest】pytest -@pytest.mark.parametrize` 装饰器-参数化测试功能

目录

基础概念及简单示例

pytest 的参数化测试功能允许我们为相同的测试函数提供多组不同的输入数据和预期输出,从而确保在各种情况下测试逻辑的正确性。这大大增强了测试的健壮性和覆盖率,特别是当测试逻辑需要处理多种边界条件或输入变化时。

要使用 pytest 的参数化测试功能,你需要使用 @pytest.mark.parametrize 装饰器。这个装饰器接受两个参数:一个字符串,表示测试函数参数的名称;一个值列表,其中每个值都是一组输入数据(通常是一个元组或列表)。

下面是一个简单的例子,演示了如何使用参数化测试来验证一个简单的加法函数:

python 复制代码
# content of test_example.py

def add(x, y):
    return x + y

# 使用 @pytest.mark.parametrize 进行参数化测试
@pytest.mark.parametrize("x, y, expected", [
    (1, 2, 3),
    (0, 0, 0),
    (-1, 1, 0),
    (1.5, 1.5, 3.0),
])
def test_add(x, y, expected):
    assert add(x, y) == expected

在这个例子中,test_add 函数会运行四次,每次使用 @pytest.mark.parametrize 装饰器中提供的一组不同的 (x, y, expected) 值。每次运行时,xy 是输入参数,expected 是期望的返回结果。测试函数通过 assert 语句来验证 add(x, y) 的结果是否等于 expected

当你运行这个测试文件时(例如,通过命令行 pytest test_example.py),你会看到四个测试案例的结果。如果所有案例都通过,那么你的加法函数就针对这些输入数据进行了充分的验证。

参数化测试特别适用于测试那些接受多种不同类型输入或需要处理多种边界条件的函数。通过使用参数化测试,你可以确保你的代码在各种情况下都能正常工作,从而提高代码的质量和可靠性。

实例

当然可以,下面是一个更复杂的例子,它展示了如何使用 pytest 的参数化测试功能来测试一个处理用户输入的函数。这个函数负责验证输入,并根据不同的输入返回不同的结果。

假设我们有一个函数 process_user_input,它接受一个字符串作为输入,并根据输入内容返回相应的处理结果:

python 复制代码
# user_processor.py

def process_user_input(input_string):
    if input_string.lower() == 'yes':
        return 'User confirmed.'
    elif input_string.lower() == 'no':
        return 'User declined.'
    elif input_string.isdigit():
        return f'You entered a number: {int(input_string)}'
    else:
        raise ValueError('Invalid input.')

现在,我们想要测试这个函数以确保它对于不同的输入能够返回正确的结果,并且在遇到无效输入时能够抛出异常。我们可以使用 pytest 的参数化测试功能来编写多个测试用例:

python 复制代码
# test_user_processor.py

import pytest
from user_processor import process_user_input

# 参数化测试数据
test_data = [
  # 测试输入 'yes' 时,期望返回 'User confirmed.'  
    ('yes', 'User confirmed.'),
    ('NO', 'User declined.'),  # 注意这里大小写应该不敏感
    ('123', 'You entered a number: 123'),
 # 测试输入无效字符串 'abc' 时,期望抛出 ValueError 异常
    ('abc', pytest.raises(ValueError)),  # 预期抛出异常
    ('', pytest.raises(ValueError)),      # 空字符串也是无效输入
    ('   ', pytest.raises(ValueError)),    # 空格也是无效输入
]

# 使用 @pytest.mark.parametrize 装饰器,将测试数据参数化到测试函数中  
@pytest.mark.parametrize("input_string, expected_result", test_data)  
def test_process_user_input(input_string, expected_result):  
    # 检查期望结果是否是异常类型  
    if isinstance(expected_result, type):  
        # 如果是异常类型,使用 pytest.raises 上下文管理器来断言函数会抛出该异常  
        with pytest.raises(expected_result):  
            process_user_input(input_string)  
    else:  
        # 如果不是异常类型,使用 assert 语句来断言函数的返回值与期望结果匹配  
        assert process_user_input(input_string) == expected_result  
  
# 运行测试时,pytest 会自动找到并执行此文件中的测试函数

在这个例子中,test_data 是一个包含多组测试数据的列表,每组数据都是一个元组,其中包含输入字符串和期望的结果。对于期望抛出异常的测试用例,我们使用 pytest.raises 作为期望结果。

test_process_user_input 函数使用 @pytest.mark.parametrize 装饰器来接收这些测试数据,并针对每一组数据运行一次测试。在测试函数中,我们首先检查 expected_result 是否是一个异常类型;如果是,我们使用 pytest.raises 上下文管理器来断言函数会抛出该异常。如果 expected_result 不是异常类型,我们则使用 assert 语句来断言函数的返回值与期望结果相匹配。

运行这个测试文件(例如,通过命令行 pytest test_user_processor.py),pytest 会为 test_process_user_input 函数中的每一组测试数据运行一次测试,并报告结果。这允许我们全面验证 process_user_input 函数在各种情况下的行为。

相关推荐
chao_78920 分钟前
二分查找篇——搜索旋转排序数组【LeetCode】一次二分查找
数据结构·python·算法·leetcode·二分查找
烛阴29 分钟前
Python装饰器解除:如何让被装饰的函数重获自由?
前端·python
workflower37 分钟前
MDSE和敏捷开发相互矛盾之处:方法论本质的冲突
数据库·软件工程·敏捷流程·极限编程
Tony小周1 小时前
实现一个点击输入框可以弹出的数字软键盘控件 qt 5.12
开发语言·数据库·qt
noravinsc1 小时前
django 一个表中包括id和parentid,如何通过parentid找到全部父爷id
python·django·sqlite
lifallen1 小时前
Paimon 原子提交实现
java·大数据·数据结构·数据库·后端·算法
ajassi20001 小时前
开源 python 应用 开发(三)python语法介绍
linux·python·开源·自动化
沉默媛1 小时前
如何安装python以及jupyter notebook
开发语言·python·jupyter
TDengine (老段)2 小时前
TDengine 数据库建模最佳实践
大数据·数据库·物联网·时序数据库·tdengine·涛思数据
Elastic 中国社区官方博客2 小时前
Elasticsearch 字符串包含子字符串:高级查询技巧
大数据·数据库·elasticsearch·搜索引擎·全文检索·lucene