• pytest系列教程——8、fixture函数中使用参数


    问题背景

    因为测试用例的多样性,我们不能硬编码,比如登录的fixture,不能只写入固定的登录用户名和密码,一个是不方便后期维护,另外一个是不好拓展。
    在之前的代码中我们发现,fixture是没办法直接传参的,举个例子:

    import pytest
    
    
    @pytest.fixture
    def login(name ,password):
        print(f"用户{name},使用密码{password}登录成功")
    
    
    
    def test_01(login):
        login("admin","123456")
        print("正在执行test01")
    
    def test_02(login):
        login("user01","666666")
        print("正在执行test02")
    
    
    if __name__ == '__main__':
        pytest.main(['fixture传参.py', '-s'])
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    目的很简单,执行casetest_01的时候使用admin账号,执行casetest_02的时候,使用user01的账号。但是 执行的时候就报错了:

    @pytest.fixture
    def login(name ,password):
    E       fixture 'name' not found
    
    • 1
    • 2
    • 3

    好像fixture 默认接受的参数必须是另外一个fixture,但是又不存在另外一个叫name的fixture,所以此时就报异常。
    所以,为了解决这一问题,我们要学习新的知识点:@pytest.mark.parametrize

    @pytest.mark.parametrize传递参数

    之前在讲fixture的参数 params的时候,讲到过request的使用:

    import pytest
    
    
    # 定义的夹具函数,使用装饰器pytest.fixture
    @pytest.fixture(params=["胡八万","胡三条","胡七筒"])
    def login(request):
        temp = request.param
        print(f"login:用户{temp}执行登录操作")
    
        return temp
    
    
    #当fixture 的params参数 会被循环执行
    def test_01(login):
        print(f"{login}已经登录成功~")
    
    
    if __name__ == '__main__':
        pytest.main(['MyPytest.py', '-s'])
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    执行结果:

    collected 3 items
    
    MyPytest.py login:用户胡八万执行登录操作
    胡八万已经登录成功~
    .login:用户胡三条执行登录操作
    胡三条已经登录成功~
    .login:用户胡七筒执行登录操作
    胡七筒已经登录成功~
    .
    
    ============================== 3 passed in 0.07s ==============================
    
    ***Repl Closed***
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    request是fixture的传参的固定写法
    为了解决上述问题,我们使用@pytest.mark.parametrize 配合request可以完美解决:

    import pytest
    
    
    @pytest.fixture
    def login(request):
        param = request.param
        print(f"用户{param['name']},使用密码{param['password']}登录成功")
    
    
    data01 = [{'name': 'admin', 'password': '123456'}]
    
    @pytest.mark.parametrize("login", data01, indirect=True)
    def test_01(login):
        print("正在执行test01")
    
    
    data02 = [{'name': 'user01', 'password': '666666'}]
    
    @pytest.mark.parametrize("login", data02, indirect=True)
    def test_02(login):
        print("正在执行test02")
    
    
    if __name__ == '__main__':
        pytest.main(['fixture传参.py', '-s'])
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    执行结果:

    collected 2 items
    
    fixture传参.py 
    
    用户admin,使用密码123456登录成功
    正在执行test01
    .
    用户user01,使用密码666666登录成功
    正在执行test02
    .
    
    ============================== 2 passed in 0.07s ==============================
    
    ***Repl Closed***
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    参数讲解

    indirect = True 是将login作为一个函数去执行,而不是一个参数,data则是这个函数的入参。
    data本质是一个列表,如果入参是fixture是单个入参,则data可以定义为:

    data = [“key1”,“key2”,… …]

    那么执行case则遍历执行key1key2

    如果fixture是多个参数的入参,则data需要传入字典形式:

    data=[{“key1”:“value1”},{“key2”:“value2”}… … ]

    同理函数遍历执行{"key1":"value1"}, {"key2":"value2"}的场景

    使用多个fixture的入参

    @pytest.mark.parametrize 叠加使用
    import pytest
    
    
    @pytest.fixture
    def openBrowser(request):
        """打开不同类型的浏览器"""
        browserType = request.param
        print(f"正在使用{browserType}浏览器")
    
    
    @pytest.fixture
    def login(request):
        param = request.param
        print(f"用户{param['name']},使用密码{param['password']}登录成功")
    
    
    browserTypes = ["IE"]
    userInfo = [{'name': 'admin', 'password': '123456'}]
    
    
    @pytest.mark.parametrize("login", userInfo, indirect=True)
    @pytest.mark.parametrize("openBrowser", browserTypes, indirect=True)
    def test_01(openBrowser, login):
        print("正在执行test01")
    
    
    if __name__ == '__main__':
        pytest.main(['fixture传参.py', '-s'])
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    运行结果:

    collected 1 item
    
    fixture传参.py 
    正在使用IE浏览器
    用户admin,使用密码123456登录成功
    正在执行test01
    .
    
    ============================== 1 passed in 0.07s ==============================
    
    ***Repl Closed***
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    @pytest.mark.parametrize 合并使用
    import pytest
    
    
    @pytest.fixture
    def openBrowser(request):
        """打开不同类型的浏览器"""
        browserType = request.param
        print(f"正在使用{browserType}浏览器")
    
    
    @pytest.fixture
    def login(request):
        param = request.param
        print(f"用户{param['name']},使用密码{param['password']}登录成功")
    
    
    data = [('IE', {'name': 'admin', 'password': '123456'})]
    
    
    @pytest.mark.parametrize("openBrowser,login", data, indirect=True)
    def test_01(openBrowser, login):
        print("正在执行test01")
    
    
    if __name__ == '__main__':
        pytest.main(['fixture传参.py', '-s'])
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    执行结果:

    
    fixture传参.py 
    正在使用IE浏览器
    用户admin,使用密码123456登录成功
    正在执行test01
    .
    ============================== 1 passed in 0.07s ==============================
    
    ***Repl Closed***
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    如果我们想测试多种场景即可改动data的数据,进行参数化:

    import pytest
    
    
    @pytest.fixture
    def openBrowser(request):
        """打开不同类型的浏览器"""
        browserType = request.param
        print(f"正在使用{browserType}浏览器")
    
    
    @pytest.fixture
    def login(request):
        param = request.param
        print(f"用户{param['name']},使用密码{param['password']}登录成功")
    
    
    data = [('IE', {'name': 'admin', 'password': '123456'}),('IE', {'name': 'root', 'password': '888888'}),('Chrome', {'name': 'admin', 'password': '123456'})]
    
    
    @pytest.mark.parametrize("openBrowser,login", data, indirect=True)
    def test_01(openBrowser, login):
        print("正在执行test01")
    
    
    if __name__ == '__main__':
        pytest.main(['fixture传参.py', '-s'])
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    执行结果:

    fixture传参.py 正在使用IE浏览器
    用户admin,使用密码123456登录成功
    正在执行test01
    .正在使用IE浏览器
    用户root,使用密码888888登录成功
    正在执行test01
    .正在使用Chrome浏览器
    用户admin,使用密码123456登录成功
    正在执行test01
    .
    
    ============================== 3 passed in 0.07s ==============================
    
    ***Repl Closed***
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
  • 相关阅读:
    PowerDotNet平台化软件架构设计与实现系列(13):应用监控平台
    Dubbo深度解析
    Django后端开发——ORM
    【clickhouse专栏】单机版的安装与验证
    13.10其他集合类(血干JAVA系类)
    Kubernetes(K8S第三部分之资源控制器)
    在Linux上安装RStudio工具并实现本地远程访问【内网穿透】
    Charles
    网络安全笔记-SSRF
    透光率检测对激光焊接的作用是什么呢?
  • 原文地址:https://blog.csdn.net/bo_mask/article/details/125421041