目录
基础概念及简单示例
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)
值。每次运行时,x
和 y
是输入参数,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
函数在各种情况下的行为。