• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

pytest系列——fixture函数使用pytest测试框架测试固件

武飞扬头像
测试中二
帮助1

前言

setup和teardown能实现在测试用例执行之前或之后做一些操作,但是这种是整个测试脚本全局生效的;

如果我们想实现某些用例执行之前进行登录,某些用例执行之前不需要进行登录,这种场景我们再使用setup和teardown就无法实现了,这时候我们就需要用到fixture功能了。

fixture函数

fixture(scope="function", params=None, autouse=False, ids=None, name=None)

参数说明:

1、scope:fixture函数的作用域;可选值:function(默认)、class、module、session

  • function:作用于每个方法或函数,每个方法或函数都运行一次
  • class:作用于整个class类,每个class中的所有test只运行一次
  • module:作用于整个模块,每个module中的所有test只运行一次
  • session:作用于整个session,整个session只运行一次(慎用)

2、params:列表类型;一个可选的参数列表;它将会多次调用被fixture标记的方法和所有用到这个fixture的test测试用例;默认为None;当前调用参数可以用 request.param 来获取。

3、autouse:如果为True,则为所有测试用例激活fixture,运行测试用例的时候会自动运行被fixture标记的方法;如果为False,则需要显示指定来激活fixture,不会自动运行。

4、ids:id字符串列表,与params相对应,因此它们也是测试的一部分。如果没有提供ids,那么将会从params来自动生成。

5、name:fixture的名称。默认为被fixture装饰器标记的函数名。

fixture的使用

1、通过参数引用fixture函数

举例:

  1.  
    # file_name:test_fixture.py
  2.  
     
  3.  
     
  4.  
    import pytest
  5.  
     
  6.  
     
  7.  
    class Test_A:
  8.  
     
  9.  
    @pytest.fixture()
  10.  
    def before(self):
  11.  
    print("\n--------before fixture has ran--------")
  12.  
     
  13.  
    def test_a(self, before): # test_a方法以参数的形式传入了被fixture标记的函数,fixture的名称默认为被fixture标记的函数名
  14.  
    print('-------test_a has ran-------')
  15.  
    assert 1
  16.  
     
  17.  
     
  18.  
    if __name__ == '__main__':
  19.  
    pytest.main(['-s', 'test_fixture.py'])
学新通

运行结果:

学新通

从结果中可以看到被fixture标记的函数before会优先于测试用例test_a运行。

2、通过使用name参数来引用fixture函数

①name参数表示fixture的重命名;

②通常来说使用 fixture 的测试函数会将 fixture 的函数名作为参数传递,但是 pytest 也允许将fixture重命名。

举例1:

  1.  
    # file_name:test_fixture.py
  2.  
     
  3.  
     
  4.  
    import pytest
  5.  
     
  6.  
     
  7.  
    class Test_A:
  8.  
     
  9.  
    @pytest.fixture(name="before_fixture_name")
  10.  
    def before(self):
  11.  
    print("\n--------before fixture has ran--------")
  12.  
     
  13.  
    def test_a(self, before_fixture_name): # test_a方法以参数的形式传入了被fixture标记的函数,这里的fixture名称为:before_fixture_name,如果不设置name参数,则fixture的名称默认为被fixture标记的函数名
  14.  
    print('-------test_a has ran-------')
  15.  
    assert 1
  16.  
     
  17.  
     
  18.  
    if __name__ == '__main__':
  19.  
    pytest.main(['-s', 'test_fixture.py'])
学新通

举例2:为fixture函数重命名之后,不可以在使用fixture函数的函数名来调用,只能通过fixture函数重命名的新名字来调用。

学新通

3、通过@pytest.mark.usefixtures('fixture函数名')函数的形式引用fixture函数

举例:

  1.  
    # file_name: test_fixture.py
  2.  
     
  3.  
     
  4.  
    import pytest
  5.  
     
  6.  
     
  7.  
    @pytest.fixture() # 被fixture标记的函数也可以应用在测试类的外部,使用@pytest.mark.usefixtures()装饰器来引用
  8.  
    def before():
  9.  
    print("\n--------before fixture has ran--------")
  10.  
     
  11.  
     
  12.  
    @pytest.mark.usefixtures("before") # 通过使用usefixtures()来引用fixture,此时usefixtures()函数的入参是fixture函数的函数名
  13.  
    class Test_A:
  14.  
     
  15.  
    def test_a(self):
  16.  
    print('-------test_a has ran-------')
  17.  
    assert 1
  18.  
     
  19.  
     
  20.  
    if __name__ == '__main__':
  21.  
    pytest.main(['-s', 'test_fixture.py'])
学新通

运行结果:

学新通

从结果中可以看到被fixture标记的函数before会优先于测试用例test_a运行。

4、通过autouse=True设置默认执行fixture函数

①fixture函数的autouse参数默认等于False;

②fixture函数的autouse参数若为True,刚每个测试函数都会自动调用该fixture函数,而且无需传入fixture函数名。

举例:

  1.  
    # file_name: test_fixture.py
  2.  
     
  3.  
     
  4.  
    import pytest
  5.  
     
  6.  
     
  7.  
    @pytest.fixture(autouse=True) # 通过参数autouse=True来设置fixture默认运行
  8.  
    def before():
  9.  
    print("\n--------before fixture has ran--------")
  10.  
     
  11.  
     
  12.  
    class Test_A:
  13.  
     
  14.  
    def test_a(self):
  15.  
    print('-------test_a has ran-------')
  16.  
    assert 1
  17.  
     
  18.  
    def test_b(self):
  19.  
    print('-------test_b has ran-------')
  20.  
    assert 1
  21.  
     
  22.  
     
  23.  
    if __name__ == '__main__':
  24.  
    pytest.main(['-s', 'test_fixture.py'])
学新通

运行结果:

学新通

从结果中可以看到我们并没有显示指定test_a和test_b使用fixture,但是在执行测试用例之前却执行了fixture,这就是因为我们将fixture设置成了autouse=True。

5、fixture作用域设置成function

举例:

  1.  
    # file_name: test_fixture.py
  2.  
     
  3.  
     
  4.  
    import pytest
  5.  
     
  6.  
     
  7.  
    @pytest.fixture(scope="function", autouse=True) # 作用域设置成function,通过参数autouse=True来设置fixture默认运行
  8.  
    def before():
  9.  
    print("\n--------before fixture has ran--------")
  10.  
     
  11.  
     
  12.  
    class Test_A:
  13.  
     
  14.  
    def test_a(self):
  15.  
    print('-------test_a has ran-------')
  16.  
    assert 1
  17.  
     
  18.  
    def test_b(self):
  19.  
    print('-------test_b has ran-------')
  20.  
    assert 1
  21.  
     
  22.  
     
  23.  
    if __name__ == '__main__':
  24.  
    pytest.main(['-s', 'test_fixture.py'])
学新通

运行结果:

学新通

从结果中可以看到将fixture的作用域设置成scope=function后,每个test测试用例执行前都会执行一次被fixture标记的函数。

并且通过跟上一个例子对比我们可以看到设置 scope=function 和不设置scope参数的执行结果是一致的,这说明scope参数的默认值是function。

6、fixture作用域设置成class

举例:

  1.  
    # file_name: test_fixture.py
  2.  
     
  3.  
     
  4.  
    import pytest
  5.  
     
  6.  
     
  7.  
    @pytest.fixture(scope="class", autouse=True) # 作用域设置成class,通过参数autouse=True来设置fixture默认运行
  8.  
    def before():
  9.  
    print("\n--------before fixture has ran--------")
  10.  
     
  11.  
     
  12.  
    class Test_A:
  13.  
     
  14.  
    def test_a(self):
  15.  
    print('-------test_a has ran-------')
  16.  
    assert 1
  17.  
     
  18.  
    def test_b(self):
  19.  
    print('-------test_b has ran-------')
  20.  
    assert 1
  21.  
     
  22.  
     
  23.  
    if __name__ == '__main__':
  24.  
    pytest.main(['-s', 'test_fixture.py'])
学新通

运行结果:

学新通

从运行结果中可以看到测试类中有两个测试用例,但是fixture却只执行了一次。

7、fixture的返回值使用

举例:

  1.  
    # file_name: test_fixture.py
  2.  
     
  3.  
     
  4.  
    import pytest
  5.  
     
  6.  
     
  7.  
    @pytest.fixture()
  8.  
    def return_data():
  9.  
    print("\n--------before fixture has ran--------")
  10.  
    return 2 # 返回值
  11.  
     
  12.  
     
  13.  
    class Test_A:
  14.  
     
  15.  
    def test_a(self, return_data):
  16.  
    print('-------test_a has ran-------')
  17.  
    assert 1 == return_data # 拿到返回值做断言
  18.  
     
  19.  
     
  20.  
    if __name__ == '__main__':
  21.  
    pytest.main(['-s', 'test_fixture.py'])
学新通

运行结果:

学新通

从结果中看到我们拿到了fixture的返回值为2,在测试用例中拿到返回值做断言,断言失败。

8、fixture的params参数使用

①params形参是fixture函数的可选形参列表,支持列表传入;

②不传此参数时默认为None;

③每个param的值fixture函数都会去调用执行一次,类似for循环。

④可与参数ids一起使用,作为每个参数的标识,类似于用例参数化时的ids作用。

举例:

  1.  
    # file_name: test_fixture.py
  2.  
     
  3.  
     
  4.  
    import pytest
  5.  
     
  6.  
     
  7.  
    @pytest.fixture(params=[1, 2, 3])
  8.  
    def return_data(request): # 传入参数request,request系统内置的fixture
  9.  
    print("\n--------before fixture has ran--------")
  10.  
    return request.param # 通过request.param 获取当前传入的参数
  11.  
     
  12.  
     
  13.  
    class Test_A:
  14.  
     
  15.  
    def test_a(self, return_data):
  16.  
    print('-------test_a has ran,return_data的值为:{}-------'.format(return_data))
  17.  
    assert 1 == return_data # 拿到返回值做断言
  18.  
     
  19.  
     
  20.  
    if __name__ == '__main__':
  21.  
    pytest.main(['-s', 'test_fixture.py'])
学新通

运行结果:

学新通

从结果中我们可以看到测试用例执行了3次。通过设置params参数会导致多次调用被fixture标记的函数,并且使用该fixture函数的测试用例也会执行多次。

学新通

9、fixture的params参数于ids参数结合使用

①fixture函数未配置ids参数之前:用例执行后的标识为传入的params参数。

学新通

②fixture函数配置ids参数之后:用例执行后的标识为传入的ids参数。并与params参数一个一个地对应。

学新通

10、fixture函数的相互调用(fixture函数与fixture函数之间的依赖关系)

举例1:

  1.  
    import pytest
  2.  
    # fixtrue作为参数,互相调用传入
  3.  
    @pytest.fixture()
  4.  
    def account():
  5.  
    a = "account"
  6.  
    print("第一层fixture")
  7.  
    return a
  8.  
     
  9.  
    #Fixture的相互调用一定是要在测试类里调用这层fixture才会生次,普通函数单独调用是不生效的
  10.  
    @pytest.fixture()
  11.  
    def login(account):
  12.  
    print("第二层fixture")
  13.  
     
  14.  
    class TestLogin:
  15.  
    def test_1(self, login):
  16.  
    print("直接使用第二层fixture,返回值为{}".format(login))
  17.  
     
  18.  
    def test_2(self, account):
  19.  
    print("只调用account fixture,返回值为{}".format(account))
  20.  
     
  21.  
     
  22.  
    if __name__ == '__main__':
  23.  
    pytest.main()
学新通

运行结果1:

学新通

举例2:如果一个fixture函数依赖另外一个fixture函数,此时不能使@pytest.mark.usefixtures() 调用被依赖的fixture函数,这种调用方式不会生效。而是需要用函数传递的方式才能生效。

  1.  
    # test_fixture_02.py
  2.  
    import pytest
  3.  
     
  4.  
     
  5.  
    @pytest.fixture()
  6.  
    def login_weibo():
  7.  
    print("==============登陆微博===============")
  8.  
     
  9.  
     
  10.  
    @pytest.fixture()
  11.  
    # @pytest.mark.usefixtures("login_weibo") #这种方式不会生效
  12.  
    def get_weibo_data(login_weibo): # 这种方式才会生效
  13.  
    """fixture函数依赖,需要用传递函数的方式"""
  14.  
    print("=============获取微博数据==============")
  15.  
     
  16.  
     
  17.  
    @pytest.mark.demo
  18.  
    class TestMyCode:
  19.  
     
  20.  
    @pytest.mark.usefixtures("get_weibo_data")
  21.  
    def test_fixture_005(self):
  22.  
    """fixture函数在测试脚本文件中"""
  23.  
    assert 1 == 1
学新通

运行结果:

学新通

【注意】

①即使fixture函数之间支持相互调用,但普通函数直接使用fixture是不支持的,一定是在测试函数内调用才会逐级调用生效。

②有多层fixture函数调用时,最先执行的是最后一层fixture函数,而不是先执行传入测试函数的fixture函数。

③上层fixture函数的值不会自动return,这里就类似函数相互调用一样的逻辑。【函数调用值需要赋值给一个变量并使用】

我这里给你们分享一下我所积累和真理的文档和学习资料有需要是领取就可以了

1、学习思路和方法

这个大纲涵盖了目前市面上企业百分之99的技术,这个大纲很详细的写了你该学习什么内容,企业会用到什么内容。总共十个专题足够你学习

学新通

2、想学习却无从下手,该如何学习?

这里我准备了对应上面的每个知识点的学习资料、可以自学神器,已经项目练手。

学新通

学新通

3、软件测试/自动化测试【全家桶装】学习中的工具、安装包、插件....

学新通

学新通

学新通

4、有了安装包和学习资料,没有项目实战怎么办,我这里都已经准备好了往下看

学新通

最后送上一句话:
世界的模样取决于你凝视它的目光,自己的价值取决于你的追求和心态,一切美好的愿望,不在等待中拥有,而是在奋斗中争取。
如果我的博客对你有帮助、如果你喜欢我的文章内容,请 “点赞” “评论” “收藏” 一键三连哦!

学新通

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhfjaiif
系列文章
更多 icon
同类精品
更多 icon
继续加载