Pytest系列-数据驱动@pytest.mark.parametrize(7)

2023-09-13 20:55:39

简介

unittest 和 pytest参数化对比:
pytest与unittest的一个重要区别就是参数化,unittest框架使用的第三方库ddt来参数化的

而pytest框架:

  • 前置/后置处理函数fixture,它有个参数params专门与request结合使用来传递参数,也可以用parametrize结合request来传参
  • 针对测试方法参数化就直接使用装饰器@pytest.mark.parametrize来对测试用例进行传参

参数化目的

  • 参数化,就是把测试过程中的数据提取出来,通过参数传递不同的数据来驱动用例运行。其实也就是数据驱动的概念
  • 当测试用例只有测试数据和期望结果不一样,但操作步骤是一样的时,可以用参数化提高代码复用性,减少代码冗余

参数化实际应用举例

Web UI自动化中的开发场景,比如是一个登录框:

1、需要测试账号空、密码空、账号密码都为空、账号不存在、密码错误、账号密码正确等情况
2、这些用例的区别就在于输入的测试数据和对应的交互结果
3、所以我们可以只写一条登录测试用例,然后把多组测试数据和期望结果参数化,节省很多代码量

Pytest参数化

语法

@pytest.mark.parametrize(args_name,args_values,indirect=False, ids=None,scope=None)

参数列表

  • args_name:参数名称,用于参数值传递给函数
  • args_values:参数值:(列表和列表字典,元组和字典元组),有n个值那么用例执行n次。
  • indirect:默认为False,代表传入的是参数。如果设置成True,则把传进来的参数当函数执行,而不是一个参数。
  • ids:自定义测试id,字符串列表,ids的长度需要与测试数据列表的长度一致,标识每一个测试用例,自定义测试数据结果的显示,为了增加可读性
  • scope:如果指定,则表示参数的范围。
    范围用于按参数实例对测试进行分组。
    它还将覆盖任何夹具功能定义的范围,允许使用测试上下文或配置设置动态范围。

使用方法

1、单个参数

​​@pytest.mark.parametrize()​​ 装饰器接收两个参数,一个参数是以字符串的形式标识用例函数的参数,第二个参数以列表或元组的形式传递测试数据

import pytest
#待测试数据
def add(a,b):
    return a+b

# 单个参数的情况
@pytest.mark.parametrize("a",[1,2,3,4])
def test_add(a):  # 作为用例参数,接收装饰器传入的数据
    print(" a的值:",a)
    assert add(a,1) == a+1

执行结果
在这里插入图片描述

2、多个参数

多个参数,​​@pytest.mark.parametrize()​​第一个参数依然是字符串, 对应用例的多个参数,用逗号分隔,实际是一个解包的过程。

import pytest

def add(a,b):
    return a+b

@pytest.mark.parametrize("a,b,c",[(1,2,3),(4,5,9),('1','2','12')])
def test_add(a,b,c):
    print(f"\n a,b,c的值:{a},{b},{c}")
    assert add(a,b)==c

在这里插入图片描述
执行结果
在这里插入图片描述

3、整个测试类参数化

测试类的参数化,其实际上也是对类中的测试方法进行参数化。
当装饰器 @pytest.mark.parametrize 装饰测试类时,会将数据集合传递给类的所有测试用例方法

import pytest

data= [(1,2,3),(4,5,9)]

@pytest.mark.parametrize("a,b,c",data)
class TestStudy:
    def test_parametrize_one(self,a,b,c):
        print(f"\n 测试函数111  测试数据为 {a}-{b}")
        assert a+b ==c

    def test_parametrize_two(self, a, b, c):
        print("\n 测试函数222  测试数据为 {}-{}".format(a,b))
        assert a + b == c

执行结果
在这里插入图片描述

4、多个参数叠加相乘

多个参数组合时使用的是笛卡尔积
笛卡尔积:

  • 一个函数或一个类可以装饰多个 @pytest.mark.parametrize
  • 这种方式,最终生成的用例数是nm,比如上面的代码就是:参数a的数据有3个,参数b的数据有2个,所以最终的用例数有32=6条
  • 当参数化装饰器有很多个的时候,用例数都等于n * n * n* n *…
# 笛卡尔积,组合数据
data_1=[1,2,3]
data_2=['a','b']

@pytest.mark.parametrize('a',data_1)
@pytest.mark.parametrize('b',data_2)
def test_parametrize_one(a,b):
    print(f"笛卡尔积 测试数据为:{a}{b}")

执行结果
在这里插入图片描述
参数化,传入字典

# 字典
data_1=(
    {
        'user':1,
        'pwd':2
    },
    {
        'user':3,
        'pwd':4
    }
)

@pytest.mark.parametrize('dic',data_1)
def test_parametrize_1(dic):
    print(f"测数据为 \n {dic}")
    print(f"user:{dic['user']},pwd:{dic['pwd']}")

执行结果
在这里插入图片描述
参数化,标记数据

# 标记参数化
@pytest.mark.parametrize("test_input,expected",[
    ("3+5",8),
    ("2+4",6),
    pytest.param("6 * 9",42,marks=pytest.mark.xfail),
    pytest.param("6 * 6",42,marks=pytest.mark.skip)
])
def test_parametrize_mark(test_input,expected):
    assert  eval(test_input) == expected

执行结果
在这里插入图片描述

5、ids 自定义测试id

  • ​​@pytest.mark.parametrize()​​​ 提供了 ​​ids​​ 参数来自定义显示结果,主要是为了更加清晰看到用例的含义

  • ids的长度需要与测试数据列表的长度一致,与fixture的ids参数是一样的,可参考fixture的ids。

# 增加可读性
data_1=[(1,2,3),(4,5,9)]

ids = ["a:{} + b:{} = expect:{}".format(a,b,expect) for a,b,expect in data_1]

@pytest.mark.parametrize("a,b,expect",data_1,ids=ids)
class TestParametrize(object):
    def test_parametrize_1(self,a,b,expect):
        print(f"测试函数1测试数据为 {a}--{b}")
        assert a + b ==expect

    def test_parametrize_2(self,a,b,expect):
        print("测试函数2测试数据为 {}--{}".format(a,b))
        assert  a + b == expect

执行结果
在这里插入图片描述

request 与parametrize 结合使用给 Fixture传参

  • fixture自身的params参数可以结合request来传参,详见fixture的其他参数介绍章节,当然也可以用parametrize来参数化代替params

  • indirect=True参数,目的是把传入的data当做函数去执行,而不是参数

  • 如果测试方法写在类中,则 @pytest.mark.parametrize 的参数名称要与 @pytest.fixture 函数名称保持一致

应用场景:

  • 为了提高复用性,我们在写测试用例的时候,会用到不同的fixture,比如:最常见的登录操作,大部分的用- 例的前置条件都是登录
  • 假设不同的用例想登录不同的测试账号,那么登录fixture就不能把账号写死,需要通过传参的方式来完成登录操作

1、单个参数

@pytest.fixture()
def test_demo(request):
    name = request.param
    yield name
    print(f"==测试数据是:{name}==")


data=["ceshi","qianduan"]
ids=[f"test_name is:{name}" for name in data]

@pytest.mark.parametrize("test_demo",data,ids=ids,indirect=True)
def test_name(test_demo):
    print(f"测试用例的数据是:{test_demo}")

执行结果
在这里插入图片描述
知识点:

  • 添加 indirect=True 参数是为了把 test_demo 当成一个函数去执行,而不是一个参数并且将data当做参数传入函数
  • def test_name(test_demo) ,这里的 test_demo 是获取fixture返回的值

2、多个参数

@pytest.fixture()
def logins(request):
    param = request.param
    yield param
    print(f"账号是:{param['username']},密码是:{param['pwd']}")

data =[
    {"username":"张三","pwd":"123456"},
    {"username":"李四","pwd":"12345"}
]

@pytest.mark.parametrize("logins",data,indirect=True)
def test_name_pwd(logins):
    print(f"账号是:{logins['username']},密码是:{logins['pwd']}")

执行结果
在这里插入图片描述
如果需要传多个参数,需要通过字典去传

3、多个fixture(只加一个装饰器)和多个parametrize(叠加装饰器)

# 多个fixture
@pytest.fixture()
def login_user(request):
    user = request.param
    yield user
    print("账号:%s" % user)

@pytest.fixture()
def login_pwd(request):
    pwd = request.param
    yield pwd
    print("密码:%s" % pwd)

data =[
    {"username":"张三","pwd":"123456"},
    {"username":"李四","pwd":"12345"}
]

@pytest.mark.parametrize("login_user,login_pwd",data,indirect=True)
def test_more_fixture(login_user,login_pwd):
    print("fixture返回的内容:",login_user,login_pwd)

执行结果
在这里插入图片描述

@pytest.fixture(scope="function")
def login_user(request):
    user = request.param
    yield user
    print("账号:%s" % user)

@pytest.fixture(scope="function")
def login_pwd(request):
    pwd = request.param
    yield pwd
    print("密码:%s" % pwd)

name= ["张三","李四"]
pwd = ["123456","12345"]

@pytest.mark.parametrize("login_user",name,indirect=True)
@pytest.mark.parametrize("login_pwd",pwd,indirect=True)
def test_more_fixture(login_user,login_pwd):
    print("fixture返回的内容:",login_user,login_pwd)

执行结果
在这里插入图片描述

[参考文章] 小菠萝测试笔记

更多推荐

Learn Prompt-角色扮演

模拟面试​当你在新闻中读到更多关于ChatGPT的内容时,你会听说ChatGPT可以代替医生、面试官、教师、律师等。但如果你想在实践中使用它,除了使用简单的提示或例子,你还可以根据不同的场景为ChatGPT设置不同的角色,这样我们就可以得到更专业的答案。让我们从一个简单的例子开始:首先我们可以让ChatGPT担任面试官

Improving 3D Imaging with Pre-Trained Perpendicular 2D Diffusion Models

使用预先训练的垂直2D扩散模型改进3D成像论文链接:https://arxiv.org/abs/2303.08440项目链接:https://github.com/hyn2028/tpdmAbstract扩散模型由于其众多的优点已经成为一种流行的图像生成和重建方法。然而,大多数基于扩散的逆问题解决方法只处理2D图像,甚

【数据结构-树】红黑树

💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。推荐:kuan的首页,持续学习,不断总结,共同进步,活到老学到老导航檀越剑指大厂系列:全面总结java核心技术点,如集合,jvm,并发编程redis,kaf

创造音乐的无限可能——Ableton Live 11 Suite for Mac音乐制作软件

如果您是一位音乐创作者,那么AbletonLive11SuiteforMac将是您实现创意的完美伴侣。作为一款全面且强大的音乐制作软件,它为您提供了一系列令人惊叹的工具和功能,帮助您打造出独一无二的音乐作品。AbletonLive11SuiteforMac是一款为专业音乐制作而设计的软件。它具备直观、灵活的界面,使您能

麒麟信安参编的两项云计算团体标准发布!助推云计算产业高质量发展

近日,由中国电子技术标准化研究院主办,全国信标委云计算和分布式平台分委会、全国信标委云计算标准工作组、云计算标准与应用工业和信息化部重点实验室承办的第十二届云计算标准和应用大会在北京举办。本次大会上,麒麟信安起草参编的《信息技术云计算智能云服务用户体验度量模型》《信息技术云计算边缘云协同技术要求》两项团体标准正式发布!

LabVIEW应用开发——前面板和程序框图

上篇我们讲述了LabVIEW的安装并且新建了一个VI程序成功运行,这篇我们详细了解界面上一些工具、属性和层次结构。LabVIEW安装我们双击打开上次创建的.vi文件。这时候我们发现只有前面板,程序框图界面不见了,我们需要使用Ctrl+E或者在Windows-->ShowBlockDiagram选项中把程序框图调出来。而

科技活动类型

声明本文是学习GB-T42776-2023科技评估分类.而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们1范围本文件确立了科技评估的分类原则,描述了分类方法,规定了编码方法、分类与代码。本文件适用于科技评估的规划、设计、委托、组织、实施、管理、研究、培训和信息化等相关活动。2规范性引用文件下列文件中

MYSQL索引——B+树讲解

B-/B+树看MySQL索引结构B-树B-树,这里的B表示balance(平衡的意思),B-树是一种多路自平衡的搜索树.它类似普通的平衡二叉树,不同的一点是B-树允许每个节点有更多的子节点。下图是B-树的简化图.B-树有如下特点:所有键值分布在整颗树中;任何一个关键字出现且只出现在一个结点中;搜索有可能在非叶子结点结束

睿趣科技:抖音开一家网店大概什么时候回本

随着移动互联网的迅猛发展,社交媒体平台如抖音成为了商家推广产品和服务的热门渠道之一。许多人都希望能够通过在抖音上宣传自己的产品,甚至考虑开一家网店,但回本的时间是一个关键问题。本文将探讨抖音开一家网店大概什么时候回本的问题。首先,回本时间的长短与多种因素有关,包括产品的类型、市场竞争、推广策略等。一般来说,如果你的产品

性能测试之压力测试

文章目录一.基本介绍二.性能指标三.下载安装JMeter1.下载安装包2.启动JMeter四.使用JMeter1.模拟用户请求2.填写测试地址3.接收测试结果4.结果解释一.基本介绍压力测试考察当前软硬件条件下系统所能承受的最大负荷并找到系统瓶颈所在。压测是为了系统在线上的处理能力和稳定性维持在一个范围内。压力测试可以

Mysql——压缩包方式安装教程

一.Mysql压缩包下载方式zip版(5.7及8.0)的下载需到官方网站下载,不同版本对应能安装在不同的操作系统下,本次介绍的是mysql-8.0.30-winx64在win10下的安装方式。下载网址:MySQL::DownloadMySQLCommunityServer二.Mysql的安装流程1.下载压缩包至本机目录

热文推荐