当前位置: 代码迷 >> 综合 >> pytest(9): fixture,定义,使用,参数化
  详细解决方案

pytest(9): fixture,定义,使用,参数化

热度:77   发布时间:2023-11-21 17:37:43.0

fixture是在测试函数运行前后,由pytest执行的外壳函数。fixture中的代码可以定制,满足多变的测试需求,包括定义传入测试中的数据集,配置测试前系统的初始状态,为批量测试提供数据源,等等。

#!/usr/bin/python3
#-*- conding:utf-8 -*-
import pytest @pytest.fixture()
def fixturefun():return 2def test_one(fixturefun):assert fixturefun == 2
==================================== test session starts =====================================
platform linux -- Python 3.5.3, pytest-5.4.2, py-1.8.1, pluggy-0.13.1
rootdir: /media/_dde_data/python
collected 1 item                                                                             test_001.py .                                                                          [100%]===================================== 1 passed in 0.02s ======================================

fixture

@pytest.fixture()装饰器用于声明函数是一个fixture,如果测试用例的参数中包含此fixture函数,则在测试用例运行前会先运行此fixture函数。如果fixture函数有返回值,则将返回值传递给测试用例函数

一. 调用方式

1.使用fixture名字作为参数

#!/usr/bin/python3
#-*- conding:utf-8 -*-
import pytest@pytest.fixture()
def fixturetest():print('fixturetest')def test_1(fixturetest):print('test_1')

 2.使用 @pytest.mark.usefixtures('fixture') 装饰器

#!/usr/bin/python3
#-*- conding:utf-8 -*-
import pytest@pytest.fixture()
def fixturetest():print('fixturetest')@pytest.mark.usefixtures('fixturetest')
def test_2():print('test_2')

3. 使用autouse参数所有test_*自动执行fixture

  1. 使用autouse参数所有test_*自动执行fixture
#!/usr/bin/python3
#-*- conding:utf-8 -*-
import pytest@pytest.fixture(autouse=True)
def fixturetest():print('fixturetest')def test_1():print('test_1')def test_2():print('test_2')class Test_class():def test_3(self):print('test_3')
结果:  
================================================== test session starts ===================================================  
platform linux -- Python 3.5.3, pytest-5.4.2, py-1.8.1, pluggy-0.13.1  
rootdir: /media/_dde_data/python  
collected 3 items                                                                                                          test2.py fixturetest  
test_1  
.fixturetest  
test_2  
.fixturetest  
test_3  
.  =================================================== 3 passed in 0.01s ====================================================  

usefixtures与传fixture区别

如果fixture有返回值,那么usefixture就无法获取到返回值,这个是装饰器usefixture与用例直接传fixture参数的区别。

当fixture需要用到return出来的参数时,只能讲参数名称直接当参数传入,不需要用到return出来的参数时,两种方式都可以。

二. 使用fixture传递测试数据

#!/usr/bin/python3
#-*- conding:utf-8 -*-
import pytest @pytest.fixture()
def fixturefun():return (1,2,3,4)def test_one(fixturefun):assert fixturefun[0] == 2
==================================== test session starts =====================================
platform linux -- Python 3.5.3, pytest-5.4.2, py-1.8.1, pluggy-0.13.1
rootdir: /media/_dde_data/python
collected 1 item                                                                             test_001.py SETUP    F fixturefuntest_001.py::test_one (fixtures used: fixturefun)FTEARDOWN F fixturefun========================================== FAILURES ==========================================
__________________________________________ test_one __________________________________________fixturefun = (1, 2, 3, 4)def test_one(fixturefun):
>       assert fixturefun[0] == 2
E       assert 1 == 2test_001.py:10: AssertionError
================================== short test summary info ===================================
FAILED test_001.py::test_one - assert 1 == 2
===================================== 1 failed in 0.18s ======================================

三. 使用多个fixture

#!/usr/bin/python3
#-*- conding:utf-8 -*-
import pytest @pytest.fixture()
def fixturefun1():print ("**********fixture_1***********")@pytest.fixture()
def fixturefun2():print ("**********fixture_2***********")def test_one(fixturefun1,fixturefun2):print("测试用例")
==================================== test session starts =====================================
platform linux -- Python 3.5.3, pytest-5.4.2, py-1.8.1, pluggy-0.13.1
rootdir: /media/_dde_data/python
collected 1 item                                                                             test_001.py **********fixture_1***********
**********fixture_2***********
测试用例
.===================================== 1 passed in 0.01s ======================================

 四.使用yield实现teardown

@pytest.fixture()
def fixturetest():print('setup')yieldprint('teardown')

例:

#!/usr/bin/python3
#-*- conding:utf-8 -*-
import pytest@pytest.fixture(scope='class',autouse=True)
def fixturetest():print('----------开始-------------')yieldprint('----------结束-------------')class Test_class1():def test_1(self):print('test_1')def test_2(self):print('test_2')class Test_class2():def test_a(self):print('test_a')def test_b(self):print('test_b')
==================================== test session starts =====================================
platform linux -- Python 3.5.3, pytest-5.4.2, py-1.8.1, pluggy-0.13.1
rootdir: /media/_dde_data/python
collected 4 items                                                                                                        test2.py ----------开始-------------
test_1
.test_2
.----------结束-------------
----------开始-------------
test_a
.test_b
.----------结束-------------===================================== 4 passed in 0.02s ======================================

五.作用范围

scope参数可以是session, module,class,function; 默认为function

  • session 会话级别:
    每个session只运行一次,session级别的fixture需要定义到conftest.py中

  • module 模块级别:
    模块里所有的用例执行前执行一次module级别的fixture

  • class 类级别 :
    每个类执行前都会执行一次class级别的fixture

  • function :
    前面实例已经说了,这个模式是默认的模式,函数级别的,每个测试用例执行前都会执行一次function级别的fixture

目录结构:

.
├── conftest.py
├── __init__.py
├── test_001.py
└── test_002.py
#conftest.py
import pytest@pytest.fixture(scope="session",autouse="True")
def sess_scope():print('----------开始session-------------')yieldprint('----------结束session-------------')@pytest.fixture(scope="module",autouse="True")
def mod_scope():print('----------开始module-------------')yieldprint('----------结束module-------------')@pytest.fixture(scope="class",autouse="True")
def class_scope():print('----------开始class-------------')yieldprint('----------结束class-------------')@pytest.fixture(scope="function",autouse="True")
def fun_scope():print('----------开始function-------------')yieldprint('----------结束function-------------')
#test_001.py
#!/usr/bin/python3
#-*- conding:utf-8 -*-
import pytest def test_one():print("函数用例 1")class Test_Class1():def test_two(self):print("类 1 用例 2")def test_three(self):print("类 1 用例 3")def test_four():print("函数用例 4")
#test_002.py
#!/usr/bin/python3
#-*- conding:utf-8 -*-
import pytest def test_1():print("函数用例 5")class Test_Class2():def test_6(self):print("类 2 用例 6")def test_7(self):print("类 2 用例 7")def test_4():print("函数用例 8")
==================================== test session starts =====================================
platform linux -- Python 3.5.3, pytest-5.4.2, py-1.8.1, pluggy-0.13.1
rootdir: /media/_dde_data/python
collected 8 items                                                                            test_001.py ----------开始session-------------
----------开始module-------------
----------开始class-------------
----------开始function-------------
函数用例 1
.----------结束function-------------
----------结束class-------------
----------开始class-------------
----------开始function-------------
类 1 用例 2
.----------结束function-------------
----------开始function-------------
类 1 用例 3
.----------结束function-------------
----------结束class-------------
----------开始class-------------
----------开始function-------------
函数用例 3
.----------结束function-------------
----------结束class-------------
----------结束module-------------test_002.py ----------开始module-------------
----------开始class-------------
----------开始function-------------
函数用例 5
.----------结束function-------------
----------结束class-------------
----------开始class-------------
----------开始function-------------
类 2 用例 6
.----------结束function-------------
----------开始function-------------
类 2 用例 7
.----------结束function-------------
----------结束class-------------
----------开始class-------------
----------开始function-------------
函数用例 8
.----------结束function-------------
----------结束class-------------
----------结束module-------------
----------结束session-------------===================================== 8 passed in 0.03s ======================================

此例中发现当作用范围时class(autouse="True")级别时,其实函数用例(类之外的)运行前后也都会运行

六. 为fixture重命名

fixture允许使用@pytest.fixturename参数对fixture重命名

#!/usr/bin/python3
#-*- conding:utf-8 -*-
import pytest @pytest.fixture(name='fix')
def fixturefun():print("**********fixture*************")@pytest.mark.usefixtures('fix')
def test_one():print("函数用例 1")
==================================== test session starts =====================================
platform linux -- Python 3.5.3, pytest-5.4.2, py-1.8.1, pluggy-0.13.1
rootdir: /media/_dde_data/python
collected 1 item                                                                             test_001.py **********fixture*************
函数用例 1
.===================================== 1 passed in 0.01s ======================================

七.fixture参数化

使用pytest的内建fixturerequest实现参数化

#!/usr/bin/python3
#-*- conding:utf-8 -*-
import pytesttest_param = [(1,2),("a","b"),(False,False),(int,int)]
@pytest.fixture(params=test_param)
def fixturefun(request):test = request.paramreturn testdef test_001(fixturefun):assert fixturefun[0] == fixturefun[1]
==================================== test session starts =====================================
platform linux -- Python 3.5.3, pytest-5.4.2, py-1.8.1, pluggy-0.13.1 -- /usr/bin/python3
cachedir: .pytest_cache
rootdir: /media/_dde_data/python
collected 4 items                                                                            test_001.py::test_001[fixturefun0] FAILED                                              [ 25%]
test_001.py::test_001[fixturefun1] FAILED                                              [ 50%]
test_001.py::test_001[fixturefun2] PASSED                                              [ 75%]
test_001.py::test_001[fixturefun3] PASSED                                              [100%]========================================== FAILURES ==========================================
___________________________________ test_001[fixturefun0] ____________________________________fixturefun = (1, 2)def test_001(fixturefun):
>       assert fixturefun[0] == fixturefun[1]
E       assert 1 == 2
E         +1
E         -2test_001.py:13: AssertionError
___________________________________ test_001[fixturefun1] ____________________________________fixturefun = ('a', 'b')def test_001(fixturefun):
>       assert fixturefun[0] == fixturefun[1]
E       AssertionError: assert 'a' == 'b'
E         - b
E         + atest_001.py:13: AssertionError
================================== short test summary info ===================================
FAILED test_001.py::test_001[fixturefun0] - assert 1 == 2
FAILED test_001.py::test_001[fixturefun1] - AssertionError: assert 'a' == 'b'
================================ 2 failed, 2 passed in 0.20s =================================

fixture和@pytest.mark.parametrize结合的参数化

#!/usr/bin/python3
#-*- conding:utf-8 -*-
import pytesttest_param = [(1,2),("a","b"),(False,False),(int,int)]
@pytest.fixture()
def fixturefun(request):test = request.paramreturn test@pytest.mark.parametrize("fixturefun",test_param,indirect=True) #indirect=True 声明fixturefun不是参数,而是一个函数
def test_001(fixturefun):assert fixturefun[0] == fixturefun[1]

参考:pytest-fixture - 静心&得意 - 博客园

  相关解决方案