6:参数化

承接前两篇:Pytest 用例规则 + 前后置 + 原生 assert 断言,本篇讲解参数化,接口自动化核心必备。日常接口需要覆盖正常、异常、边界多组入参,参数化实现「一套用例代码,多组数据循环执行」,大幅减少重复代码。

一、什么是参数化,为什么自动化必须用?

1. 概念

@pytest.mark.parametrize是 pytest 内置装饰器,批量传入多组测试数据,自动循环生成多条独立测试用例,一组数据对应 1 次用例执行。

2. 解决痛点

不使用参数化:多组入参就要复制多份测试函数,代码冗余、后期维护困难; 使用参数化:只写 1 次用例逻辑,数据源统一维护,新增 / 删减数据不用改动业务代码,接口边界、异常场景全覆盖。

接口测试场景:登录接口(正确账号、密码为空、错误密码、手机号格式错误)4 种场景,参数化 1 行配置 4 组数据即可。

二、基础语法格式

python 复制代码
@pytest.mark.parametrize(参数名字符串, 数据集列表)
def test_xxx(参数名):
    # 测试逻辑+断言
  • 第一个入参:"参数1,参数2" 多个参数用英文逗号分隔;
  • 第二个入参:嵌套列表 / 元组,每组元素一一对应前面的参数。

三、四种常用参数化写法(从单参数→类→全局→自定义数据源)

写法 1:函数级别参数化(单 / 多参数,项目最常用)

① 多参数传参(示例:计算器表达式校验,文档原示例优化)
python 复制代码
import pytest
# 参数1:计算公式字符串,参数2:预期结果
@pytest.mark.parametrize("test_input,expected", [("3+5", 8), ("2+4", 6), ("6*9", 42)])
def test_eval(test_input, expected):
    # 执行计算公式
    res = eval(test_input)
    # 结合上篇断言知识点
    assert res == expected, f"公式{test_input}预期{expected},实际{res}"

执行pytest -vs,自动生成3 条独立用例 ,其中6*9=54≠42会单独失败,精准定位出错数据。

② 单参数简易示例
python 复制代码
@pytest.mark.parametrize("phone",["13800138000","","123456"])
def test_phone_format(phone):
    # 校验手机号长度
    assert len(phone)==11,f"手机号{phone}长度非法"

写法 2:测试类上参数化(类内所有 test 方法共用一套数据源)

装饰器写在 class 上方,类中全部以 test 开头的方法自动继承参数,每组数据所有方法循环执行一遍

python 复制代码
import pytest
# 两个参数 n:入参数字,expected:预期结果
@pytest.mark.parametrize("n,expected", [(1, 2), (3, 4)])
class TestClass:
    def test_simple_case(self, n, expected):
        assert n + 1 == expected
    def test_weird_simple_case(self, n, expected):
        assert (n * 1) + 1 == expected

执行结果:2 组数据 × 2 个用例 = 总共 4 条测试用例。

写法 3:模块全局参数化(当前 py 文件全部用例统一数据)

在脚本顶部定义全局变量pytestmark,本文件所有测试类、测试函数自动复用参数,不用逐个加装饰器

python 复制代码
import pytest
# 全局参数配置,本模块所有用例自动带入n、expected参数
pytestmark = pytest.mark.parametrize("n,expected", [(1, 2), (3, 4)])

class TestClass:
    def test_simple_case(self, n, expected):
        assert n + 1 == expected
    def test_weird_simple_case(self, n, expected):
        assert (n * 1) + 1 == expected

# 类外函数同样自动参数化
def test_global_demo(n,expected):
    assert n+1 == expected

写法 4:自定义函数返回数据源(数据和代码分离,实战优选)

把测试数据单独封装函数,后续拓展:从 json/yaml/excel 读取用例数据,实现数据代码完全分离

python 复制代码
import pytest
# 自定义数据源函数,后续可改成读取文件
def data_provider():
    return ["a", "b"]

# 直接传入函数名,自动读取返回列表
@pytest.mark.parametrize("data", data_provider())
def test_data(data):
    assert data is not None
    print(f"Testing with data provider: {data}")

拓展:企业项目中data_provider()内部写读取 yaml 接口用例,是主流接口自动化方案。

四、接口自动化实战案例(落地场景,结合 requests + 断言)

python 复制代码
import pytest
import requests

# 接口参数:帖子id,预期用户id
@pytest.mark.parametrize("post_id,expect_uid",[(1,1),(2,2),(99,99)])
def test_post_api(post_id,expect_uid):
    url = f"https://jsonplaceholder.typicode.com/posts/{post_id}"
    res = requests.get(url)
    # 断言状态码
    assert res.status_code == 200,f"接口{url}请求异常"
    json_data = res.json()
    # 校验返回用户id
    assert json_data["userId"] == expect_uid,f"帖子{post_id}预期用户{expect_uid},实际{json_data['userId']}"

执行后 3 个接口分别发起请求,任意一组数据出错单独标记失败,不影响其他用例执行。

五、进阶实用小技巧

1. 给每组用例自定义用例名称(ids 参数)

默认用例名是参数内容,可读性差,通过ids给每组数据起名,报告清晰

python 复制代码
@pytest.mark.parametrize("user,pwd",[("admin","123456"),("admin","")],ids=["正常登录","密码空登录"])
def test_login(user,pwd):
    pass

执行日志直接显示:test_login[正常登录]test_login[密码空登录]

2. 跳过指定参数用例(pytest.mark.skipif)

部分测试数据临时不需要执行,动态跳过单组用例

python 复制代码
data = [(1,2),(3,4)]
@pytest.mark.parametrize("n,e",data)
def test_skip(n,e):
    if n ==3:
        pytest.skip("该场景暂未开发完成,临时跳过")
    assert n+1 ==e

六、常见踩坑总结

  1. 参数数量匹配:参数名几个,每组元组必须对应相同元素,否则直接报参数不匹配报错;
  2. 全局 pytestmark 优先级:函数单独写了 parametrize 会覆盖全局配置;
  3. 数据分离规范:项目用例多了不要把数据硬编码写在装饰器里,统一放到函数 / 配置文件。
相关推荐
Avan_菜菜8 小时前
FRP 内网穿透完整实战:从 HTTP 映射到 HTTPS 自签代理
运维·nginx·https
SelectDB1 天前
Litefuse 开源并推出单进程轻量模式,25 秒就能跑起来的 Agent 可观测与评估平台
运维·后端·自动化运维
zzzzzz3103 天前
9K Star 炸裂开源!这个 C 语言写的代码知识图谱,把 Linux 内核索引压缩到了 3 分钟
linux·服务器·sql
XIAOHEZIcode3 天前
Linux系统鼠标偏移常见原因以及修复方案
linux·运维·游戏
用户0328472220703 天前
如何搭建本地yum源(上)
运维
大树886 天前
金刚石散热越强,管路越先见顶
大数据·运维·服务器·人工智能·ai
摇滚侠6 天前
Linux CentOS7 rpm 安装 MySQL 5.7
linux·运维·mysql
霸道流氓气质6 天前
领域驱动设计(DDD)在 Spring Boot 微服务中的实践指南
运维·spring boot·微服务
小宇宙Zz6 天前
Maven依赖冲突
java·服务器·maven
Inhand陈工6 天前
基于台达PLC与映翰通IG502的智慧水产养殖精准投喂与远程运维解决方案
运维·人工智能·物联网·阿里云·信息与通信