7. Pytest参数化:parametrize参数详解(了解)

一、前言

上节课我们讲解了如何用parametrize装饰器进行参数化,它有5个参数,argnames, argvalues, indirect, ids, scope,本节课针对这五个参数做详细讲解。

二、学习目标

1.argnames、argvalues参数实例讲解

2.indirect参数实例讲解

3.ids参数实例讲解

4.scope参数实例讲解

5.与其它mark一起使用

三、知识点

1.【argnames、argvalues参数实例讲解】

  • 单参数单值

    代码示例:

    #测试用例文件test_XXX.py
    import pytest
    
    class TestCase():
        
        @pytest.mark.parametrize('arg', [1]) #单参数单值,值必须是列表
        def test_one_params(self,arg):
            print("传入的值:{}".format(arg))
    

    运行效果:

    test-demo7.py::TestCase::test_one_params[1] PASSED                       [100%]传入的值:1
    ============================== 1 passed in 0.01s ==============================  
    
  • 单参数多值

    1.单参数多值,argvalues可以传入多样的python数据类型:列表,嵌套了元组的列表,字典,字符串
    2.传入多个值时,测试用例会被执行多次,每次取一个值去运行

    代码示例:

    #测试用例文件test_XXX.py
    import pytest
    
    
    class TestCase():
    
        @pytest.mark.parametrize('arg', ['abc',1,{'a':1,'b':3},(4,5)]) #值列表中传入了四组数据
        def test_one_params(self,arg):
            print("传入的值:{}".format(arg))
    

    运行效果:

    test-demo7.py::TestCase::test_one_params[abc] PASSED                     [ 25%]传入的值:abc
    test-demo7.py::TestCase::test_one_params[1] PASSED                       [ 50%]传入的值:1
    test-demo7.py::TestCase::test_one_params[arg2] PASSED                    [ 75%]传入的值:{'a': 1, 'b': 3}
    test-demo7.py::TestCase::test_one_params[arg3] PASSED                    [100%]传入的值:(4, 5)
    ============================== 4 passed in 0.02s ============================== #同一个测试用例分别用四组值执行了四遍
    
  • 多参数多值

    argnames参数的个数,必须要和argvalues的每一组的个数一致,否则报错。

    代码示例:

    #测试用例文件test_XXX.py
    import pytest
    
    
    @pytest.mark.parametrize("test_input,expected",[("3+5",8),("5-2",3),("5*2",10)])#test_input,expected分别对应每个元组中的两个值
    def test_params(test_input,expected):
        print("原值:{} 期望值{}".format(test_input,expected))
        assert eval(test_input) == expected
    

    运行效果:

    test-demo7.py::test_params[3+5-8] PASSED                                 [ 33%]原值:3+5 期望值8
    test-demo7.py::test_params[5-2-3] PASSED                                 [ 66%]原值:5-2 期望值3
    test-demo7.py::test_params[5*2-10] PASSED                                [100%]原值:5*2 期望值10
    ============================== 3 passed in 0.02s ==============================
    
  • parametrize叠加使用:

    代码示例:

    #测试用例文件test_XXX.py
    import pytest
    
    @pytest.mark.parametrize("arg2",["a","b","c"])
    @pytest.mark.parametrize("arg1",["1","2","3"])
    def test_params(arg1,arg2):
        all = arg1 + arg2
        print("叠加组合的值:{}".format(all))
    

    运行效果:

    test-demo7.py::test_params[1-a] PASSED                                   [ 11%]叠加组合的值:1a
    test-demo7.py::test_params[1-b] PASSED                                   [ 22%]叠加组合的值:1b
    test-demo7.py::test_params[1-c] PASSED                                   [ 33%]叠加组合的值:1c
    test-demo7.py::test_params[2-a] PASSED                                   [ 44%]叠加组合的值:2a
    test-demo7.py::test_params[2-b] PASSED                                   [ 55%]叠加组合的值:2b
    test-demo7.py::test_params[2-c] PASSED                                   [ 66%]叠加组合的值:2c
    test-demo7.py::test_params[3-a] PASSED                                   [ 77%]叠加组合的值:3a
    test-demo7.py::test_params[3-b] PASSED                                   [ 88%]叠加组合的值:3b
    test-demo7.py::test_params[3-c] PASSED                                   [100%]叠加组合的值:3c
    ============================== 9 passed in 0.04s ============================== 
    

2.【indirect参数实例讲解】

说明:

​ (一)indirect一般与Pytest的request、fixture组合使用。

​ (二)当indrect 为True时,argnames则要传入fixture函数名称,不再是一个普通参数,而是要被调用的fixture函数,argvalues则是要给这个函数传的值。

​ (三)作法其实与@pytest.fixture(params)一样,但使用了@pytest.mark.parametrize相当于参数化了fixture,而不是只有固定的一套数据传入使用。

  • 单fixture单值(通过列表)

    代码示例:

    #conftest.py前置定义文件
    import pytest
    
    @pytest.fixture()
    def indirect_demo(request):
        user = request.param
        print("传入的用户名为:{}".format(user))
        yield user
    
    #测试用例文件test_XXX.py
    import pytest
    user = ['张三','李四']
    
    @pytest.mark.parametrize('indirect_demo',user,indirect=True)
    def test_one_param(indirect_demo):
        print("测试类的读到的用户是:{}".format(indirect_demo))
    

    运行结果:

    test-demo7.py::test_one_param[\u5f20\u4e09] 传入的用户名为:张三
    PASSED                       [ 50%]测试类的读到的用户是:张三
    
    test-demo7.py::test_one_param[\u674e\u56db] 传入的用户名为:李四
    PASSED                       [100%]测试类的读到的用户是:李四
    ============================== 2 passed in 0.02s ==============================
    
  • 单fixture多值(通过字典)

    代码示例:

    #conftest.py前置定义文件
    import pytest
    
    @pytest.fixture()
    def indirect_demo2(request):
        user = request.param
        print("传入的用户名为:{},密码为:{}".format(user['user'],user['pwd']))
        yield user
    
    #测试用例文件test_XXX.py
    import pytest
    
    userinfo  = [
        {'user':'张三','pwd':123},
        {'user':'李四','pwd':456}
    ]
    
    @pytest.mark.parametrize('indirect_demo2',userinfo,indirect=True)
    def test_one_param(indirect_demo2):
        print("测试类的读到的用户是:{} 密码是:{}".format(indirect_demo2['user'],indirect_demo2['pwd']))
    
    

    运行结果:

    test-demo7.py::test_one_param[indirect_demo20] 传入的用户名为:张三,密码为:123
    PASSED                    [ 50%]测试类的读到的用户是:张三 密码是:123
    test-demo7.py::test_one_param[indirect_demo21] 传入的用户名为:李四,密码为:456
    PASSED                    [100%]测试类的读到的用户是:李四 密码是:456
    ============================== 2 passed in 0.01s ==============================
    
  • 传多fixture多值(通过嵌套元组的列表)

    代码示例:

    #conftest.py前置定义文件
    import pytest
    
    @pytest.fixture()
    def indirect_demo3(request):
        user = request.param
        print("传入的用户名为:{}".format(user))
        return user
    
    @pytest.fixture()
    def indirect_demo4(request):
        pwd = request.param
        print("传入的密码为:{}".format(pwd))
        return pwd
    
    #测试用例文件test_XXX.py
    import pytest
    
    userinfo  = [
        ('张三',123),
        ('李四','pwd')
    ]
    
    @pytest.mark.parametrize('indirect_demo3,indirect_demo4',userinfo,indirect=True)
    def test_one_param(indirect_demo3,indirect_demo4):
        print("测试类的读到的用户是:{} 密码是:{}".format(indirect_demo3,indirect_demo4))
    
    

    运行结果:

    test-demo7.py::test_one_param[\u5f20\u4e09-123] 传入的用户名为:张三
    传入的密码为:123
    PASSED                   [ 50%]测试类的读到的用户是:张三 密码是:123
    
    test-demo7.py::test_one_param[\u674e\u56db-pwd] 传入的用户名为:李四
    传入的密码为:pwd
    PASSED                   [100%]测试类的读到的用户是:李四 密码是:pwd
    ============================== 2 passed in 0.02s ==============================
    
  • 叠加fixture(单值列表)

    代码示例:

    #conftest.py前置定义文件
    import pytest
    @pytest.fixture()
    def indirect_demo3(request):
        user = request.param
        print("传入的用户名为:{}".format(user))
        return user
    
    @pytest.fixture()
    def indirect_demo4(request):
        pwd = request.param
        print("传入的密码为:{}".format(pwd))
        return pwd
    
    #测试用例文件test_XXX.py
    import pytest
    
    user = ['张三','李四']
    pwd  = [124,345]
    
    @pytest.mark.parametrize('indirect_demo3',pwd,indirect=True)
    @pytest.mark.parametrize('indirect_demo4',user,indirect=True)
    def test_one_param(indirect_demo3,indirect_demo4):
        print("测试类的读到的用户是:{} 密码是:{}".format(indirect_demo3,indirect_demo4))
    

    运行结果:

    test-demo7.py::test_one_param[\u5f20\u4e09-124] 传入的用户名为:124
    传入的密码为:张三
    PASSED                   [ 25%]测试类的读到的用户是:124 密码是:张三
    
    test-demo7.py::test_one_param[\u5f20\u4e09-345] 传入的用户名为:345
    传入的密码为:张三
    PASSED                   [ 50%]测试类的读到的用户是:345 密码是:张三
    
    test-demo7.py::test_one_param[\u674e\u56db-124] 传入的用户名为:124
    传入的密码为:李四
    PASSED                   [ 75%]测试类的读到的用户是:124 密码是:李四
    
    test-demo7.py::test_one_param[\u674e\u56db-345] 传入的用户名为:345
    传入的密码为:李四
    PASSED                   [100%]测试类的读到的用户是:345 密码是:李四
    ============================== 4 passed in 0.03s ==============================
    

3.【ids参数实例讲解】

作用:标记子用例执行名称,增加可读性,中文需要转码

代码示例:

#测试用例文件test_XXX.py
import pytest

userinfo  = [
    ('张三',123),
    ('李四','pwd')
]

ids = ["case{}".format(i) for i in range(len(userinfo))]


@pytest.mark.parametrize('indirect_demo3,indirect_demo4',userinfo,indirect=True,ids=ids)
def test_one_param(indirect_demo3,indirect_demo4):
    print("测试类的读到的用户是:{} 密码是:{}".format(indirect_demo3,indirect_demo4))

运行效果:

test-demo7.py::test_one_param[case0] 传入的用户名为:张三   #【】内显示自定义的ids
传入的密码为:123
PASSED                              [ 50%]测试类的读到的用户是:张三 密码是:123

test-demo7.py::test_one_param[case1] 传入的用户名为:李四
传入的密码为:pwd
PASSED                              [100%]测试类的读到的用户是:李四 密码是:pwd
============================== 2 passed in 0.02s ==============================

4.【scope参数实例讲解】

  1. scope的作用范围取值与fixture scope一致,当indirect=True才会被使用。
  2. scope的作用范围会覆盖fixture的scope范围,如果同一个被调用的fixture有多个parametrize定义了scope,取第一条的范围。

代码示例:

#conftest.py前置定义文件
import pytest
@pytest.fixture(scope="function")
def indirect_demo3(request):
    user = request.param
    print("传入的用户名为:{}".format(user))
    return user

@pytest.fixture(scope="function")
def indirect_demo4(request):
    pwd = request.param
    print("传入的密码为:{}".format(pwd))
    return pwd
#测试用例文件test_XXX.py
import pytest
userinfo  = [
    ('张三',123)
]

ids = ["case{}".format(i) for i in range(len(userinfo))]

class TestCase():

    @pytest.mark.parametrize('indirect_demo3,indirect_demo4',userinfo,indirect=True,ids=ids,scope="class")
    def test_one_param1(self,indirect_demo3,indirect_demo4):
        print("测试类的读到的用户是:{} 密码是:{}".format(indirect_demo3,indirect_demo4))

    @pytest.mark.parametrize('indirect_demo3,indirect_demo4',userinfo,indirect=True,ids=ids,scope="function")
    def test_one_param2(self,indirect_demo3,indirect_demo4):
        print("测试类的读到的用户是:{} 密码是:{}".format(indirect_demo3,indirect_demo4))

运行效果:

test-demo7.py::TestCase::test_one_param1[case0] 传入的用户名为:张三
传入的密码为:123
PASSED                   [ 50%]测试类的读到的用户是:张三 密码是:123

test-demo7.py::TestCase::test_one_param2[case0] PASSED                   [100%]测试类的读到的用户是:张三 密码是:123
============================== 2 passed in 0.02s ==============================
#前置函数的作用范围被重新定义,原来是function,用例是class。但是第二个测试用例还是class。因为两个测试用例都修改了同一个前置,以第一个为准。

5.【 与其它mark一起使用】

代码示例:

#测试用例文件test_XXX.py
import pytest
a = '跳过'
@pytest.mark.parametrize("x,y",
                         [('test1',123456),
                          pytest.param("test1",123456,marks=pytest.mark.xfail),
                          pytest.param("test1",123456,marks=pytest.mark.xfail),
                          pytest.param("test2",123456,marks=pytest.mark.skip("跳过这条用例")),
                          pytest.param("test3",123456,marks=pytest.mark.skipif(a =='跳过',reason="有条件的跳过"))
                         ]
                         )
def test_one(x,y):
    assert  x== 'test1'
    assert  y == 123456

运行效果:

test-demo7.py::test_one[test1-1234560] PASSED                            [ 20%]
test-demo7.py::test_one[test1-1234561] XPASS                             [ 40%]
test-demo7.py::test_one[test1-1234562] XPASS                             [ 60%]
test-demo7.py::test_one[test2-123456] SKIPPED                            [ 80%]
Skipped: 跳过这条用例
test-demo7.py::test_one[test3-123456] SKIPPED                            [100%]
Skipped: 有条件的跳过
=================== 1 passed, 2 skipped, 2 xpassed in 0.02s ===================
posted @ 2023-01-17 10:26  测开星辰  阅读(1164)  评论(0编辑  收藏  举报