参数化
2024-01-08 22:59:13
章节目录:
一、参数化概念
参数化是一种测试技术,它允许在测试过程中使用不同的输入参数运行相同的测试逻辑。
-
参数化的作用主要体现在以下几个方面:
- 减少重复代码:通过参数化,可以将测试逻辑与输入参数分离,避免编写多个重复的测试方法或函数。相同的测试逻辑可以在不同的参数集上自动运行,从而减少了代码冗余。
- 提高测试覆盖范围:使用参数化技术,可以轻松地定义多个输入参数组合,使测试能够覆盖更多的场景和边界条件。通过传递不同的参数值,可以测试不同的输入情况,并验证系统在各种情况下的行为是否符合预期。
- 增加可扩展性:参数化测试使得测试用例的维护和扩展更加容易。当需要增加新的测试场景或输入参数时,只需要在参数化的测试方法或函数中添加相应的参数组合,而不需要修改现有的测试逻辑。
- 提供清晰的测试报告:通过参数化测试,每个参数组合都会被视为一个独立的测试用例,并在测试报告中单独显示。这样可以更好地跟踪和分析每个测试用例的结果,找出导致失败或异常的具体输入参数组合。
-
参数化是测试框架中的一个重要特性,常用于单元测试、集成测试和功能测试等各个级别的测试。它可以提高测试的效率、可读性和维护性,帮助开发人员在不同的输入参数组合下更全面地验证系统的行为。
二、pytest 中的参数化
2.1 通过装饰器参数化
最常用的是通过装饰器
@pytest.mark.parametrize()
方式进行参数化。
- 代码示例:
import pytest
def add(a, b):
return a + b
@pytest.mark.parametrize("a,b", [[1, 2], [3, 4], [5, 6]])
# 第一个参数是以字符串的形式标识用例函数的参数。 -- "a,b"
# 第二个参数以列表或元组的形式传递测试数据。 -- [[1, 2], [3, 4], [5, 6]]
def test_case(a, b):
# 断言 a,b 之和是否小于等于 10。
assert add(a, b) <= 10
# test-demo.py::test_case[1-2] PASSED [ 33%]
# test-demo.py::test_case[3-4] PASSED [ 66%]
# test-demo.py::test_case[5-6] FAILED [100%]
- 注意:
- 多个参数之间要用逗号分隔。
- 参数名称和个数要一一对应。
2.2 通过读取文件参数化
这里以读取 yaml 文件为例,同样也可以将测试数据通过 json 文件进行管理。
- 项目结构:
F:\PROJECTS\TEST-DEMO
│
├─cases
│ test_login.py
│ __init__.py
│
├─data
│ login.yaml
│ __init__.py
│
├─utils
│ file_utils.py
│ __init__.py
└─
- login.yaml:
- case_name: "账号密码正确"
user_name: "root"
password: 666666
- case_name: "用户名为空"
user_name:
password: 666666
- case_name: "密码为空"
user_name: "root"
password:
- file_utils.py:
import yaml
def read_yaml(yaml_file_path):
"""
读取 YAML 文件并返回解析后的数据。
:param yaml_file_path: YAML 文件的路径
:return: 解析后的 YAML 数据
:raises: IOError, yaml.YAMLError
"""
try:
with open(yaml_file_path, "r", encoding="utf-8") as f:
value = yaml.safe_load(stream=f)
except IOError:
# 处理文件读取错误。
raise
except yaml.YAMLError:
# 处理 YAML 解析错误。
raise
return value
if __name__ == '__main__':
print(read_yaml(r'../data/login.yaml'))
- test_login.py:
import pytest
from utils.file_utils import read_yaml
@pytest.mark.parametrize("case", read_yaml(r"../data/login.yaml"))
def test_login(case):
user_name = case["user_name"]
password = case["password"]
assert user_name == "root" and password == 666666
# PASSED [ 33%]
# {'case_name': '用户名为空', 'password': 666666, 'user_name': None} FAILED [ 66%]
# {'case_name': '密码为空', 'password': None, 'user_name': 'root'} FAILED [100%]
2.3 对测试类进行参数化
测试类的参数化,其实际上也是对类中的测试方法进行参数化。类中的测试方法的参数必须与
@pytest.mark.parametrize()
中的标识的参数个数一致。
- 代码示例:
import pytest
def add(a, b):
return a + b
@pytest.mark.parametrize("a,b,c", [[1, 2, 3], [1, 3, 4], [2, 5, 7]])
class TestParams:
def test_par1(self, a, b, c):
# 断言 a + b 是否等于 c。
assert add(a, b) == c
def test_par2(self, a, b, c):
assert add(a, b) == c
# def test_par3(self, a, b):
# 参数个数不一致,报错。
# assert add(a, b) > 0
# In test_par3: function uses no argument 'c'
# test_demo.py::TestParams::test_par1[1-2-3]
# test_demo.py::TestParams::test_par1[1-3-4]
# test_demo.py::TestParams::test_par1[2-5-7]
# test_demo.py::TestParams::test_par2[1-2-3]
# test_demo.py::TestParams::test_par2[1-3-4]
# test_demo.py::TestParams::test_par2[2-5-7]
#
# ============================== 6 passed in 0.01s ==============================
2.4 结合 fixture 参数化
- 代码示例:
import pytest
@pytest.fixture(scope="module")
def login(request):
return request.param
data = [
{"name": "jan", "age": 28},
{"name": "rose", "age": 19}
]
@pytest.mark.parametrize("login", data, indirect=True)
def test_login(login):
name = str(login["name"])
age = int(login["age"])
assert name.startswith("j") and age > 25
# ========================= 1 failed, 1 passed in 0.11s =========================
- “login”: 这是参数化测试的参数名称,它用于在测试函数中引用参数。
- data: 这是一个包含参数化数据的可迭代对象,它定义了多组参数值。通常是一个列表或元组,每个元素表示一组参数。
indirect=True
: 这是一个可选参数,它告诉 pytest 在运行测试函数时将参数作为fixture
解析并注入到测试函数中。通过设置indirect=True
,你可以通过定义一个与参数名称相同的fixture
函数来提供参数的值。
2.5 将参数格式化输出
通过自定义的 ids,可以提高过程参数的可读性。
- 代码示例:
import pytest
def add(a, b):
return a + b
def get_data():
"""
测试数据列表。
:return:
"""
return [[1, 2, 3], [1, 3, 4], [2, 5, 7]]
# 自定义输出信息。
ids = ["{} + {} = {}".format(a, b, c) for a, b, c in get_data()]
@pytest.mark.parametrize("a,b,c", get_data(), ids=ids)
class TestParams:
def test_par1(self, a, b, c):
# 断言 a + b 是否等于 c。
assert add(a, b) == c
# test-demo.py::TestParams::test_par1[1 + 2 = 3]
# test-demo.py::TestParams::test_par1[1 + 3 = 4]
# test-demo.py::TestParams::test_par1[2 + 5 = 7]
#
# ============================== 3 passed in 0.01s ==============================
三、补充说明
还有一些其他参数化的方式。
- 钩子函数
pytest_generate_tests
是conftest.py
文件中的一个钩子函数,用于自定义参数化测试用例的生成过程。通过编写自定义的pytest_generate_tests
函数,可以定义自己的参数化方案或扩展pytest
框架默认的参数化行为。
四、结束语
“-------怕什么真理无穷,进一寸有一寸的欢喜。”
微信公众号搜索:饺子泡牛奶。
文章来源:https://blog.csdn.net/weixin_48776531/article/details/135467270
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!