Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >Pytest学习笔记3——参数化

Pytest学习笔记3——参数化

作者头像
全栈测试开发日记
发布于 2023-02-02 09:33:01
发布于 2023-02-02 09:33:01
63500
代码可运行
举报
运行总次数:0
代码可运行

  前言

  在讲pytest与unittest的区别文章中,我们知道其中一个区别就是参数化,unittest框架使用的第三方库ddt来参数化的,而pytest框架就直接使用装饰器@pytest.mark.parametrize来对测试用例进行传参。这个是针对测试方法来参数化,还有一种是针对前置处理函数来传参。但往往这两种是可以结合使用。

  Params参数化(单个)

  前面讲fixture函数时,它有个参数params用来传递参数,并且与request结合使用,先看单个:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import pytest

seq = [1, 2, 3]


@pytest.fixture(params=seq)
def test_data(request):
    print("参数")
    return request.param


class TestData:
    def test_1(self, test_data):
        print("用例", test_data)


if __name__ == '__main__':
    pytest.main()

  运行结果:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
fixture_test03.py::TestData::test_1[1] 参数
PASSED                            [ 33%]用例 1

fixture_test03.py::TestData::test_1[2] 参数
PASSED                            [ 66%]用例 2

fixture_test03.py::TestData::test_1[3] 参数
PASSED                            [100%]用例 3


============================== 3 passed in 0.05s ==============================

  Params参数化(多个)

  列表里有多个dict数据,request会自动化循环读取每个索引下的值,从0开始,看下面例子:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import pytest

seq = [{'a':1,'b':2},{'c':3,'d':4}]


@pytest.fixture(params=seq)
def test_data(request):
    print("参数:%s"%request.param)
    return request.param


class TestData:
    def test_1(self, test_data):
        print("用例", test_data)




if __name__ == '__main__':
    pytest.main()

  运行结果:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
============================== 2 passed in 0.04s ==============================

Process finished with exit code 0
参数:{'a': 1, 'b': 2}
PASSED                   [ 50%]用例 {'a': 1, 'b': 2}
参数:{'c': 3, 'd': 4}
PASSED                   [100%]用例 {'c': 3, 'd': 4}

注意:params需要与request一起使用。

  装饰器@pytest.mark.parametrize参数化(单个)

  我们做接口测试时,编写测试用例需要输入一组数据,然后执行程序,得到输出数据,经过断言将实际结果与预期结果进行比较,从而得到这条用例执行的结果。但是输入的数据肯定不是一两个,这个时候需要参数化,比如登录的接口,我们可以用测试账号1登录,也可用账号2,账号3...进行登录,如果每一个参数写一条测试用例肯定是不行的,所以引入@pytest.mark.parametrize()装饰器进行参数化,这就是背景。

  格式:@pytest.mark.parametrize("参数名称","参数列表"),第一个是参数的名称,第二个是参数列表(list),也就是参数的值。

  如:@pytest.mark.parametrize("x",1, 2, 3)

  如:@pytest.mark.parametrize('请求方式,接口地址,传参,预期结果',('get','www.baidu.com','{"page":1}','{"code":0,"msg":"成功"})',('post','www.baidu.com','{"page":2}','{"code":0,"msg":"成功"}'))

  1、第一个参数是字符串,多个参数中间用逗号隔开

  2、第二个参数是list,多组数据用元祖类型;传三个或更多参数也是这样传。list的每个元素都是一个元组,元组里的每个元素和按参数顺序一一对应

  3、传一个参数 @pytest.mark.parametrize('参数名',list) 进行参数化

  4、传两个参数@pytest.mark.parametrize('参数名1,参数名2',[(参数1_data0, 参数2_data0),(参数1_data1, 参数2_data1)]) 进行参数化

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
seq = [1, 2, 3]

def get_data(x):
    print(x)
    pass


@pytest.mark.parametrize("x",seq)
def test_data(x):
    a = get_data(x)
    print(a)

if __name__ == '__main__':
    pytest.main()

  运行结果:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
============================== 3 passed in 0.04s ==============================

Process finished with exit code 0
PASSED                                   [ 33%]1
None
PASSED                                   [ 66%]2
None
PASSED                                   [100%]3
None

  备注:第一个函数输出的是参数值,类中的函数打印的是外面那个函数的返回值,因为没有return,默认返回是None。

  与request结合使用

  如果装饰器@pytest.mark.parametrize与request结合使用,如果测试方法写在类中,则@pytest.mark.parametrize的参数名称要与@pytest.fixture函数名称保持一致。并且要添加indirect=True参数,目的是把ss_data当做函数去执行,而不是参数。

  如:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import pytest
seq = [1,2,3]
@pytest.fixture()
def ss_data(request):
    print("参数:%s"%request.param)
    return request.param



class TestData:
    @pytest.mark.parametrize("ss_data",seq,indirect=True)
    def test_1(self,ss_data):
        print("用例", ss_data)

if __name__ == '__main__':
    pytest.main()

  运行结果:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
collecting ... collected 3 items

fixture_test03.py::TestData::test_1[1] 
fixture_test03.py::TestData::test_1[2] 
fixture_test03.py::TestData::test_1[3] 

============================== 3 passed in 0.04s ==============================

Process finished with exit code 0
参数:1
PASSED                            [ 33%]用例 1
参数:2
PASSED                            [ 66%]用例 2
参数:3
PASSED                            [100%]用例 3

  注意1:如果将@pytest.mark.parametrize参数名称改成x的执行,就会报错如:

  注意2:如果不使用fixture装饰器函数,也不使用外部函数,也是可以的,例子如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import pytest
seq = [1,2,3]

class TestData:
    @pytest.mark.parametrize("x",seq,indirect=False)
    def test_1(self,x):
        print("用例", x)

if __name__ == '__main__':
    pytest.main()

  运行结果:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
============================== 3 passed in 0.04s ==============================

Process finished with exit code 0
PASSED                            [ 33%]用例 1
PASSED                            [ 66%]用例 2
PASSED                            [100%]用例 3

  可以看出,装饰器@pytest.mark.parametrize参数传递的是参数名称了,而不是函数了。根据开关indirect自由控制,默认是False.

  装饰器@pytest.mark.parametrize参数化(多个)

   多个参数和单个参数写法差不多,只不过多个参数中间用逗号隔开,列表中用元组来分组,举个例子(不带类的测试方法和没有使用request参数):

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import pytest
seq = [(1,2),(3,4)]

def get_data(x,y):
    print(x)
    print(y)
    pass


@pytest.mark.parametrize("x,y",seq)
def test_data(x,y):
    get_data(x,y)
    # print(a)

if __name__ == '__main__':
    pytest.main()

  运行结果:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
============================== 2 passed in 0.04s ==============================

Process finished with exit code 0
PASSED                                 [ 50%]1
2
PASSED                                 [100%]3
4

  这就是把参数列表list里面的元组中两个值,看作一对参数(x,y)。

  与request结合使用

  前面介绍过单个使用的场景,现在是多个参数的时候,如何使用呢?

  其实差不多,但是需要注意一些问题,先看个例子:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import pytest
seq = [(1,2),(3,4)]

@pytest.fixture()
def get_data(request):
    x = request.param[0]
    y = request.param[1]
    print(x,111)
    print(y,222)
    # print(request.param)
    pass

# indirect=True声明x是个函数
@pytest.mark.parametrize("get_data",seq)
def test_data(get_data):
    print(get_data)

if __name__ == '__main__':
    pytest.main()

  运行结果:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
plugins: allure-pytest-2.8.6, rerunfailures-5.0
collecting ... collected 2 items

fixture_005.py::test_data[get_data0] PASSED                              [ 50%](1, 2)

fixture_005.py::test_data[get_data1] PASSED                              [100%](3, 4)


============================== 2 passed in 0.02s ==============================

Process finished with exit code 0

  我们可以看出来fixture装饰器函数根本没有执行,这是为什么呢?

  因为使用@pytest.mark.parametrize装饰器参数化时,默认是以参数而不是函数,这里的@pytest.mark.parametrize("get_data",seq)中get_data是参数名称,不是函数,如果要声明为函数,需要添加:indirect=True。

  我们将其改之,再运行:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import pytest
seq = [(1,2),(3,4)]

@pytest.fixture()
def get_data(request):
    x = request.param[0]
    y = request.param[1]
    print(x,111)
    print(y,222)
    # print(request.param)
    pass

# indirect=True声明x是个函数
@pytest.mark.parametrize("get_data",seq,indirect=True)
def test_data(get_data):
    print(get_data)

if __name__ == '__main__':
    pytest.main()

  运行结果:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
fixture_005.py::test_data[get_data0] 1 111
2 222
PASSED                              [ 50%]None

fixture_005.py::test_data[get_data1] 3 111
4 222
PASSED                              [100%]None


============================== 2 passed in 0.02s ==============================

Process finished with exit code 0

  多个fixture与@pytest.mark.parametrize组合

  用例前面可以有多个条件,参数化装饰器也可以叠加,使用parametrize装饰器叠加时,用例组合是2个参数个数相乘

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import pytest

seq1 = [1,2,3]
seq2 = [4,5,6]

@pytest.fixture()
def get_seq1(request):
    seq1 = request.param
    print("seq1:",seq1)
    return seq1

@pytest.fixture()
def get_seq2(request):
    seq2 = request.param
    print("seq2:", seq2)
    return seq2

@pytest.mark.parametrize("get_seq1",seq1,indirect=True)
@pytest.mark.parametrize("get_seq2",seq2,indirect=True)
def test_1(get_seq1,get_seq2):
    print(get_seq1,11)
    print(get_seq2,22)

if __name__ == '__main__':
    pytest.main()

  运行结果:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
collecting ... collected 9 items

fixture_test04.py::test_1[4-1] 
fixture_test04.py::test_1[4-2] 
fixture_test04.py::test_1[4-3] 
fixture_test04.py::test_1[5-1] 
fixture_test04.py::test_1[5-2] 
fixture_test04.py::test_1[5-3] 
fixture_test04.py::test_1[6-1] 
fixture_test04.py::test_1[6-2] 
fixture_test04.py::test_1[6-3] 

============================== 9 passed in 0.07s ==============================

Process finished with exit code 0
seq1: 1
seq2: 4
PASSED                                    [ 11%]1 11
4 22
seq1: 2
seq2: 4
PASSED                                    [ 22%]2 11
4 22
seq1: 3
seq2: 4
PASSED                                    [ 33%]3 11
4 22
seq1: 1
seq2: 5
PASSED                                    [ 44%]1 11
5 22
seq1: 2
seq2: 5
PASSED                                    [ 55%]2 11
5 22
seq1: 3
seq2: 5
PASSED                                    [ 66%]3 11
5 22
seq1: 1
seq2: 6
PASSED                                    [ 77%]1 11
6 22
seq1: 2
seq2: 6
PASSED                                    [ 88%]2 11
6 22
seq1: 3
seq2: 6
PASSED                                    [100%]3 11
6 22

  如果使用类,也是一样的,如图:

   seq1和seq2参数都是3个,所以总的用例数就是9个。

  单独使用@pytest.mark.parametrize参数组合

  总结

  pytest与unittest的区别之一参数化已经讲完,希望可以帮助你学习pytest框架。

  如果对你有帮助或喜欢自动化测试开发的朋友,可以加入右下方QQ交流群学习与探索,更多干货与你分享。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020-05-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
pytest文档14-函数传参和fixture传参数request
为了提高代码的复用性,我们在写用例的时候,会用到函数,然后不同的用例去调用这个函数。 比如登录操作,大部分的用例都会先登录,那就需要把登录单独抽出来写个函数,其它用例全部的调用这个登陆函数就行。 但是登录的账号不能写死,有时候我想用账号1去登录,执行用例1,用账号2去登录执行用例2,所以需要对函数传参。
上海-悠悠
2018/09/29
2.6K0
Pytest fixture之request传参
Pytest中我们经常会用到数据参数化,我们来介绍下装饰器@pytest.fixture()配合request传参的使用
王大力测试进阶之路
2019/11/28
8700
pytest封神之路第五步 参数化进阶
用过unittest的朋友,肯定知道可以借助DDT实现参数化。用过JMeter的朋友,肯定知道JMeter自带了4种参数化方式(见参考资料)。pytest同样支持参数化,而且很简单很实用。
dongfanger
2020/09/25
1K0
Python 自动化测试(三): pytest 参数化测试用例构建
在之前的文章中主要分享了 pytest 的实用特性,接下来讲 Pytest 参数化用例的构建。
霍格沃兹测试开发
2020/10/27
3.1K0
Pytest学习笔记2——前后置处理高级函数Fixture(完整篇)
  前面介绍了pytest传统的前后置处理方法,通过一些实例,知道了它对处理前后置的场景是有一定的局限性。所以才引入fixture装饰器函数,fixture是pytest的核心功能,也是亮点功能,它可以灵活的处理很多特殊的场景,利用pytest做接口测试,熟练掌握fixture的使用方法,pytest用起来才会得心应手!
全栈测试开发日记
2023/02/02
2.8K0
Pytest学习笔记2——前后置处理高级函数Fixture(完整篇)
Python测试框架pytest(07)fixture - 参数化params、和parametrize结合、ids
@pytest.mark.parametrize添加indirect=True参数是为了把login当成一个函数去执行,而不是一个参数,并且将data当做参数传入函数。
wangmcn
2022/07/26
5040
Python测试框架pytest(07)fixture - 参数化params、和parametrize结合、ids
pytest学习和使用13-Pytest的fixture如何使用request传入参数?
1 使用场景当我们为了提高用例的复用性,会用到不同的fixture,比如登陆场景;但是如果登陆场景,我们使用不同的账号进行测试,那如何来做?此时不能使用fixture把账号直接写死,需要通过传参的方式来实现。2 传单个参数# -*- coding:utf-8 -*-# 作者:NoamaNelson# 日期:2022/12/27 # 文件名称:test_request.py# 作用:fixture传参# 联系:VX(NoamaNelson)# 博客:https://blog.csdn.net/NoamaNel
虫无涯
2023/02/17
7560
Pytest系列(10) - fixture 传参数 request的详细使用
https://www.cnblogs.com/poloyy/category/1690628.html
小菠萝测试笔记
2020/06/09
3K0
Pytest fixture参数化params
unittest使用ddt来实现测试用例参数化、或parameterized实现测试用例参数化,pytest测试用例里面对应的参数可以用 parametrize 实现参数化,今天我们来了解下fixture参数化params
王大力测试进阶之路
2020/08/17
1.4K0
pytest学习和使用12-Unittest和Pytest参数化详解
1 Unittest参数化1.1 ddt1.1.1 简介数据驱动ddt可以实现测试数据与测试脚本的分离;通过ddt来将测试数据加载到脚本中;1.1.2 说明测试数据为嵌套字典的列表;测试类前加修饰@ddt;测试用例前加修饰@data()运行后用例会自动加载成多个单独的用例。1.1.3 安装pip install ddt1.1.4 版本信息C:\Users\Administrator>pip show ddtName: ddtVersion: 1.4.2Summary: Data-Driven/Decorat
虫无涯
2023/02/17
5810
自动化测试中使用Pytest Fixture?推荐10种常见用法!
Pytest 是一个功能强大的 Python 测试框架,其中的Fixture 是 Pytest 中的一个重要功能。它允许你设置一些特定的测试环境或准备测试数据,这些环境和数据可以在多个测试用例中重复使用。通过使用fixture,你可以避免在每个测试函数中编写重复的设置和清理代码,使得测试更加干净、简洁,并提高代码的可维护性。
测试开发技术
2024/10/11
1860
自动化测试中使用Pytest Fixture?推荐10种常见用法!
Pytest系列(9) - 参数化@pytest.mark.parametrize
https://www.cnblogs.com/poloyy/category/1690628.html
小菠萝测试笔记
2020/06/09
1.2K0
Pytest系列(9) - 参数化@pytest.mark.parametrize
[接口测试_B] 05 Pytest参数化处理
pytest的参数化方式 pytest.fixture()方式进行参数化,fixture装饰的函数可以作为参数传入其他函数 conftest.py 文件中存放参数化函数,可作用于模块内的所有测试用例 pytest.mark.parametrize()方式进行参数化 本节测试依然以is_leap_year.py方法作为测试目标: def is_leap_year(year): # 先判断year是不是整型 if isinstance(year, int) is not True:
苦叶子
2018/04/17
1.5K0
[接口测试_B] 05 Pytest参数化处理
pytest测试框架系列(3)-fixture和参数化
f ixture翻译过来就是固件装置,主要来配置测试资源,fixture是通过装饰器标注的。
搁浅同学
2022/07/21
9950
pytest测试框架系列(3)-fixture和参数化
pytest框架介绍(二)
前面简单介绍了如何使用pytest, 感觉介绍得太泛泛了。个人感觉,pytest的精髓在fixture. 学pytest就不得不说fixture,fixture是pytest的精髓所在,就像unittest中的setup和teardown一样,如果不学fixture那么使用pytest和使用unittest是没什么区别的(个人理解)。
赵云龙龙
2021/04/23
9030
Pytest和Allure测试框架-超详细版+实战
:1. 简单灵活,容易上手;支持参数化; 测试用例的skip和xfail 处理; 2. 能够支持简单的单元测试和复杂的功能测试,还可以用来做 selenium/appium等自动化测试、接口自动化测试 (pytest+requests); 3. pytest具有很多第三方插件,并且可以自定义扩展, 比较好 用的如 pytest-allure(完美html测试报告生成) pytest-xdist (多CPU分发)等; 4. 可以很好的和jenkins集成;** 5. **
全栈程序员站长
2022/09/17
2.3K0
Pytest和Allure测试框架-超详细版+实战
Pytest 学习(二十五)- 解决pytest参数化测试标题都一样问题
一、前言 使用参数化测试化后,allure的报告如下显示: 源代码如下: # -*- coding: utf-8 -*- # @Time : 2020/12/13 17:27 # @Author
软件测试君
2020/12/22
3360
Pytest 系列(28)- 参数化 parametrize + @allure.title() 动态生成标题
https://www.cnblogs.com/poloyy/category/1690628.html
小菠萝测试笔记
2020/10/30
1.3K0
Pytest 系列(28)- 参数化 parametrize + @allure.title() 动态生成标题
Pytest之参数化(四)
懂得UI自动化测试的人,应该都比较清楚ddt的模块,在一个测试场景中,如果是同样的测试步骤,那么使用ddt,就可以使用一个单个测试解决多个测试场景的使用。本文章主要总结pytest测试框架的参数化的应用。
无涯WuYa
2019/09/19
1.1K0
pytest文档16-标记失败xfail
当用例a失败的时候,如果用例b和用例c都是依赖于第一个用例的结果,那可以直接跳过用例b和c的测试,直接给他标记失败xfail 用到的场景,登录是第一个用例,登录之后的操作b是第二个用例,登录之后操作c是第三个用例,很明显三个用例都会走到登录。 如果登录都失败了,那后面2个用例就没测试必要了,直接跳过,并且标记为失败用例,这样可以节省用例时间。
上海-悠悠
2018/09/29
1.2K0
推荐阅读
相关推荐
pytest文档14-函数传参和fixture传参数request
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文