pytest fixture及conftest详解一 (各个参数的使用说明)

一、setup和teardown

setup:在每条测试用例开始执行前执行
testdown:在每条测试用例执行结束后执行

import pytest


class TestDemo:
    def setup(self):
        print('在测试用例开始执行前执行')

    def test_01_work(self):
        print('执行测试用例1')

    def test_02_work(self):
        print('执行测试用例2')

    def teardown(self):
        print('在测试用例开始执行后执行')


if __name__ == '__main__':
    pytest.main(['-vs','./test_demo1.py'])

执行结果

test_demo1.py::TestDemo::test_01_work 在测试用例开始执行前执行
执行测试用例1
PASSED在测试用例开始执行后执行

test_demo1.py::TestDemo::test_02_work 在测试用例开始执行前执行
执行测试用例2
PASSED在测试用例开始执行后执行


============================== 2 passed in 0.30s ==============================

二、setup_class、teardown_class

setup_class:在每个类执行前的初始化工作:比如:创建日志对象,创建数据库的连接,创建接口的请求对象
teardown_class:在每个类执行后的扫尾工作:比如:销毁日志对象,断开数据库连接

import pytest


class TestDemo:

    def setup_class(self):
        print('\n在每个类执行前的初始化工作:比如:创建日志对象,创建数据库的连接,创建接口的请求对象')

    def setup(self):
        print('在测试用例开始执行前执行')

    def test_01_work(self):
        print('执行测试用例1')

    def test_02_work(self):
        print('执行测试用例2')

    def teardown(self):
        print('在测试用例执行结束后执行')

    def teardown_class(self):
        print('\n在每个类执行后的扫尾工作:比如:销毁日志对象,断开数据库连接')


if __name__ == '__main__':
    pytest.main(['-s','./test_demo1.py'])

执行结果

test_demo1.py::TestDemo::test_01_work 
在每个类执行前的初始化工作:比如:创建日志对象,创建数据库的连接,创建接口的请求对象
在测试用例开始执行前执行
执行测试用例1
PASSED在测试用例执行结束后执行

test_demo1.py::TestDemo::test_02_work 在测试用例开始执行前执行
执行测试用例2
PASSED在测试用例执行结束后执行

在每个类执行后的扫尾工作:比如:销毁日志对象,断开数据库连接


============================== 2 passed in 0.18s ==============================

在这里插入图片描述

三、使用@pytest.fixture()装饰器来实现部分用例的前后置

1、写法

@pytest.fixture(scope=,params=,autouse=,ids=,name=)
参数说明:
scope :表示的是被@pytest.fixture标记的方法的作用域。 【function:默认,class(类),module(模块),package/session】
params:参数化(支持:列表,元祖,字典列表[{},{},{}],字典元祖[(),(),()])
autouse:True:自动执行,默认False
ids:当 使用params参数化时,给每一个值设置一个变量名,意义不大
name:给表示的是被pytest.fixture标记的方法取一个别名

2、scope传不同参数值的区别

a、function 函数级别,既每个函数执行,前后置方法也都会被执行

在这里插入图片描述
conftest.py文件

import pytest

@pytest.fixture()
def my_fixture():
    print('这是前置方法')
    yield
    print('这是后置方法')

test_demo1.py文件
特别注意1:如果只让test_01_work 执行前后置,那么就只给这个方法设置my_fixture

import pytest

class TestDemo:

    #如果只让test_01_work  执行前后置,那么就只给这个方法设置my_fixture
    def test_01_work(self,my_fixture):
        print('执行测试用例1')

    def test_02_work(self):
        print('执行测试用例2')



if __name__ == '__main__':
    pytest.main(['-vsq','./test_demo1.py'])
test_demo1.py 这是前置方法
执行测试用例1
.这是后置方法
执行测试用例2
.

============================== 2 passed in 0.21s ==============================

特别注意2:如果想让所有的方法 执行前后置,那么给所有的方法设置my_fixture

import pytest

class TestDemo:

    #如果只让test_01_work  执行前后置,那么就只给这个方法设置my_fixture
    def test_01_work(self,my_fixture):
        print('执行测试用例1')

    def test_02_work(self,my_fixture):
        print('执行测试用例2')



if __name__ == '__main__':
    pytest.main(['-vsq','./test_demo1.py'])

在这里插入图片描述

特别注意3:当用例很多的时候,每次都传这个参数,会很麻烦。fixture里面有个参数autouse,默认是False没开启的,可以设置为True开启自动使用fixture功能,这样用例就不用每次都去传参了,autouse设置为True,自动调用fixture功能。所有用例都会生效,包括类中的测试用例和类以外的测试用例。

import pytest

@pytest.fixture(scope='function',autouse=True)
def my_fixture():
    print('这是前置方法')
    yield
    print('这是后置方法')

import pytest

class TestDemo:

    def test_01_work(self):
        print('执行测试用例1')

    def test_02_work(self):
        print('执行测试用例2')

class TestDemo1:

    def test_03_work(self):
        print('执行测试用例3')

    def test_04_work(self):
        print('执行测试用例4')


if __name__ == '__main__':
    pytest.main(['-vsq','./test_demo1.py'])
这是前置方法
执行测试用例1
.这是后置方法
这是前置方法
执行测试用例2
.这是后置方法
这是前置方法
执行测试用例3
.这是后置方法
这是前置方法
执行测试用例4
.这是后置方法

b、class 类级别,既 前后置方法只执行一次

autouse:True:自动执行,默认False
conftest.py

import pytest

@pytest.fixture(scope='class',autouse=True)
def my_fixture():
    print('这是前置方法')
    yield
    print('这是后置方法')

test_demo1.py文件

import pytest

class TestDemo:

    def test_01_work(self):
        print('执行测试用例1')

    def test_02_work(self):
        print('执行测试用例2')



if __name__ == '__main__':
    pytest.main(['-vsq','./test_demo1.py'])
test_demo1.py 这是前置方法
执行测试用例1
.执行测试用例2
.这是后置方法


============================== 2 passed in 0.26s ==============================

c、module:模块级别

conftest.py

import pytest

@pytest.fixture(scope='module',autouse=True)
def my_fixture():
    print('这是前置方法')
    yield
    print('这是后置方法')


test_demo1.py文件

import pytest

class TestDemo:

    def test_01_work(self):
        print('执行测试用例1')

    def test_02_work(self):
        print('执行测试用例2')

class TestDemo1:

    def test_03_work(self):
        print('执行测试用例3')

    def test_04_work(self):
        print('执行测试用例4')


if __name__ == '__main__':
    pytest.main(['-vsq','./test_demo1.py'])
test_demo1.py::TestDemo::test_01_work 这是前置方法
执行测试用例1
PASSED
test_demo1.py::TestDemo::test_02_work 执行测试用例2
PASSED
test_demo1.py::TestDemo1::test_03_work 执行测试用例3
PASSED
test_demo1.py::TestDemo1::test_04_work 执行测试用例4
PASSED这是后置方法


======================================================== 4 passed in 0.16s ========================================================

d、package/session:模块级别

在这里插入图片描述
conftest.py

import pytest

@pytest.fixture(scope='session',autouse=True)
def my1_fixture():
    print('----这是前置方法----')
    yield
    print('----这是后置方法----')

test_demo1.py

import pytest

class TestDemo:

    def test_01_work(self):
        print('执行测试用例1')

    def test_02_work(self):
        print('执行测试用例2')

class TestDemo1:

    def test_03_work(self):
        print('执行测试用例3')

    def test_04_work(self):
        print('执行测试用例4')


if __name__ == '__main__':
    pytest.main(['-vsq','./test_demo1.py'])

test_run1.py

import pytest


class TestRun:

    def test_01_run(self):
        print('执行测试用例5')

if __name__ == '__main__':
    pytest.main(['-vs','./test_demo1.py'])
products/test_demo1.py::TestDemo::test_01_work ----这是前置方法----
执行测试用例1
PASSED
products/test_demo1.py::TestDemo::test_02_work 执行测试用例2
PASSED
products/test_demo1.py::TestDemo1::test_03_work 执行测试用例3
PASSED
products/test_demo1.py::TestDemo1::test_04_work 执行测试用例4
PASSED
users/test_run1.py::TestRun::test_01_run 执行测试用例5
PASSED----这是后置方法----


======================================================== 5 passed in 0.17s ========================================================

3、参数化使用: params

fixture的参数可以解决大量重复代码工作,比如数据库的连接、查询、关闭等.同样可以使用参数化来测试多条数据用例。

conftest.py

import pytest

@pytest.fixture(scope='function',params=['data1','data2','data3'])
def my_fixture(request):
    print('这是前置方法')
    yield request.param
    print('这是后置方法')

test_demo1.py
如果只让test_01_work执行前后置,那么就只给这个方法设置my_fixture

import pytest

class TestDemo:

    def test_01_work(self,my_fixture):
        print('执行测试用例1,',my_fixture)

    def test_02_work(self):
        print('执行测试用例2')

class TestDemo1:

    def test_03_work(self):
        print('执行测试用例3')

    def test_04_work(self):
        print('执行测试用例4')


if __name__ == '__main__':
    pytest.main(['-vsq','./test_demo1.py'])

执行结果

collected 6 items

test_demo1.py 这是前置方法
执行测试用例1, data1
.这是后置方法
这是前置方法
执行测试用例1, data2
asdata2
.这是后置方法
这是前置方法
执行测试用例1, data3
asdata3
.这是后置方法
执行测试用例2
.执行测试用例3
.执行测试用例4
.

============================== 6 passed in 0.10s ==============================

在这里插入图片描述

案例:对用户名和密码进行校验

conftest.py

import pytest

data=[{'user':'kobe','pwd':666666},
      {'user':'curry','pwd':666666},
      {'user':'james','pwd':666666},]


@pytest.fixture(scope='function',params=data)
def my_fixture(request):
    print('这是前置方法')
    yield request.param
    print('这是后置方法')

test_demo1.py

import pytest

class TestDemo:

    def test_01_work(self,my_fixture):
        print('执行测试用例1,',my_fixture)
        assert my_fixture['user']=='kobe' and my_fixture['pwd']==666666

    def test_02_work(self):
        print('执行测试用例2')


class TestDemo1:

    def test_03_work(self):
        print('执行测试用例3')

    def test_04_work(self):
        print('执行测试用例4')



if __name__ == '__main__':
    pytest.main(['-vsq','./test_demo1.py'])

执行结果

test_demo1.py 这是前置方法
执行测试用例1, {'user': 'kobe', 'pwd': 666666}
.这是后置方法
这是前置方法
执行测试用例1, {'user': 'curry', 'pwd': 666666}
F这是后置方法
这是前置方法
执行测试用例1, {'user': 'james', 'pwd': 666666}
F这是后置方法
执行测试用例2
.执行测试用例3
.执行测试用例4
.

在这里插入图片描述

4、ids参数的使用

ids也是要结合着params一起使用的。当有多个 param 时,针对每一个 param,可以指定一个id,
然后,这个 id 会变成测试用例名字的一部分。如果没有提供 id,则 id 将自动生成。

案例

conftest.py

import pytest

data=[{'user':'kobe','pwd':666666},
      {'user':'curry','pwd':666666},
      {'user':'james','pwd':666666},]


@pytest.fixture(scope='function',params=data,ids=['data1','data2','data3'])
def my_fixture(request):
    print('这是前置方法')
    yield request.param
    print('这是后置方法')

test_demo1.py

import pytest

class TestDemo:

    def test_01_work(self,my_fixture):
        print('执行测试用例1,',my_fixture)
        assert my_fixture['user']=='kobe' and my_fixture['pwd']==666666

    def test_02_work(self):
        print('执行测试用例2')


class TestDemo1:

    def test_03_work(self):
        print('执行测试用例3')

    def test_04_work(self):
        print('执行测试用例4')



if __name__ == '__main__':
    pytest.main(['-vs','./test_demo1.py'])

执行结果

collecting ... collected 6 items

test_demo1.py::TestDemo::test_01_work[data1] 这是前置方法
执行测试用例1, {'user': 'kobe', 'pwd': 666666}
PASSED这是后置方法

test_demo1.py::TestDemo::test_01_work[data2] 这是前置方法
执行测试用例1, {'user': 'curry', 'pwd': 666666}
FAILED这是后置方法

test_demo1.py::TestDemo::test_01_work[data3] 这是前置方法
执行测试用例1, {'user': 'james', 'pwd': 666666}
FAILED这是后置方法

test_demo1.py::TestDemo::test_02_work 执行测试用例2
PASSED
test_demo1.py::TestDemo1::test_03_work 执行测试用例3
PASSED
test_demo1.py::TestDemo1::test_04_work 执行测试用例4
PASSED

5、name参数的使用

当使用了别名之后,原来的名称就使用不了了。

案例

conftest.py

import pytest

data=[{'user':'kobe','pwd':666666},
      {'user':'curry','pwd':666666},
      {'user':'james','pwd':666666},]


@pytest.fixture(scope='function',params=data,ids=['data1','data2','data3'],name='fix')
def my_fixture(request):
    print('这是前置方法')
    yield request.param
    print('这是后置方法')

test_demo1.py

import pytest

class TestDemo:

    def test_01_work(self,fix):
        print('执行测试用例1,',fix)
        assert fix['user']=='kobe' and fix['pwd']==666666

    def test_02_work(self):
        print('执行测试用例2')


class TestDemo1:

    def test_03_work(self):
        print('执行测试用例3')

    def test_04_work(self):
        print('执行测试用例4')



if __name__ == '__main__':
    pytest.main(['-vs','./test_demo1.py'])

执行结果

test_demo1.py::TestDemo::test_01_work[data1] 这是前置方法
执行测试用例1, {'user': 'kobe', 'pwd': 666666}
PASSED这是后置方法

test_demo1.py::TestDemo::test_01_work[data2] 这是前置方法
执行测试用例1, {'user': 'curry', 'pwd': 666666}
FAILED这是后置方法

test_demo1.py::TestDemo::test_01_work[data3] 这是前置方法
执行测试用例1, {'user': 'james', 'pwd': 666666}
FAILED这是后置方法

test_demo1.py::TestDemo::test_02_work 执行测试用例2
PASSED
test_demo1.py::TestDemo1::test_03_work 执行测试用例3
PASSED
test_demo1.py::TestDemo1::test_04_work 执行测试用例4
PASSED

四、通过conftest.py和@pytest.fixture()结合使用来实现全局的前置应用

1、应用场景:

比如:项目的全局登录,模块的全局处理

2、conftest.py的特点

①conftest.py文件是单独存放的一个夹具配置文件,名称是不能更改的。
②可以在不同的py文件中使用同一个fixture函数
③原则上conftest.py需要和运行的用例放到同一个目录下,并且不需要做任何的import导入操作。

特别注意3
每个模块设置单独的前后置,也可以使用外部公共的前后置。
在这里插入图片描述
test_demo1.py

import pytest

class TestDemo:

    def test_01_work(self):
        print('执行测试用例1')

    def test_02_work(self):
        print('执行测试用例2')

class TestDemo1:

    def test_03_work(self):
        print('执行测试用例3')

    def test_04_work(self):
        print('执行测试用例4')


if __name__ == '__main__':
    pytest.main(['-vsq','./test_demo1.py'])

test_run1.py

import pytest


class TestRun:

    def test_01_run(self):
        print('执行测试用例5')

if __name__ == '__main__':
    pytest.main(['-vs','./test_demo1.py'])


全局conftest.py

import pytest

@pytest.fixture(scope='session',autouse=True)
def my1_fixture():
    print('----这是前置方法----')
    yield
    print('----这是后置方法----')



局部products\conftest.py

import pytest

@pytest.fixture(scope='module',autouse=True)
def my_fixture():
    print('这是前置方法')
    yield
    print('这是后置方法')



局部users\conftest

import pytest

@pytest.fixture(scope='module',autouse=True)
def my_fixture():
    print('这是前置方法')
    yield
    print('这是后置方法')

执行结果

products/test_demo1.py::TestDemo::test_01_work ----这是前置方法----
这是前置方法
执行测试用例1
PASSED
products/test_demo1.py::TestDemo::test_02_work 执行测试用例2
PASSED
products/test_demo1.py::TestDemo1::test_03_work 执行测试用例3
PASSED
products/test_demo1.py::TestDemo1::test_04_work 执行测试用例4
PASSED这是后置方法

users/test_run1.py::TestRun::test_01_run 这是前置方法
执行测试用例5
PASSED这是后置方法
----这是后置方法----

特别注意:当脚本中既有全局conftest,也有局部conftest时,先执行全局的,后执行局部的
在这里插入图片描述

五、conftest.py中的yield使用

return和yeild的区别: 都是表示返回值的意思,但是return的后面不能有代码,yeild很后面可以有代码

yield语句之前的就会在测试用例之前使用,yield之后的语句就会在测试用例执行完成之后再执行。

常见的应用场景:@pytest.fixture可以用在selenium中测试用例执行前后打开、关闭浏览器的操作;
yield返回driver对象去操作浏览器;
@pytest.fixture可以用在接口自动化测试中操作登录,yield返回token;

conftest.py

import pytest

@pytest.fixture(scope='session',autouse=True)
def login():
    token=获取到的值
    print('token的值:',token)
    yield token
    print('退出登录')

test_demo1.py

import pytest

class TestDemo:

    def test_01_work(self):
        print('执行测试用例1')

    def test_02_work(self):
        print('执行测试用例2')

class TestDemo1:

    def test_03_work(self):
        print('执行测试用例3')

    def test_04_work(self):
        print('执行测试用例4')


if __name__ == '__main__':
    pytest.main(['-vsq','./test_demo1.py'])

test_run1.py

import pytest


class TestRun:

    def test_01_run(self,login):
        print('执行测试用例5,获取到的token为:',login)

if __name__ == '__main__':
    pytest.main(['-vs','./test_demo1.py'])

执行结果

products/test_demo1.py::TestDemo::test_01_work token的值: 66666666666666666
执行测试用例1
PASSED
products/test_demo1.py::TestDemo::test_02_work 执行测试用例2
PASSED
products/test_demo1.py::TestDemo1::test_03_work 执行测试用例3
PASSED
products/test_demo1.py::TestDemo1::test_04_work 执行测试用例4
PASSED
users/test_run1.py::TestRun::test_01_run 执行测试用例5,获取到的token为: 66666666666666666
PASSED退出登录


======================================================== 5 passed in 0.13s ========================================================
  • 61
    点赞
  • 64
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 43
    评论
当我们使用pytest进行测试时,fixture和conftest是非常有用的工具。 Fixture是pytest的一个装饰器,用于在测试用例执行前后做一些准备和收尾工作。比如说,在测试用例需要使用数据库,那么我们可以使用fixture在测试用例执行前连接数据库,在测试用例执行后断开连接。这样可以避免在每个测试用例都重复写相同的代码。 下面是一个使用fixture的例子: ```python import pytest @pytest.fixture def setup_database(): # 连接数据库 yield # 断开连接 ``` 在这个例子,我们定义了一个名为setup_database的fixture,这个fixture在测试用例执行前连接数据库,在测试用例执行后断开连接。 conftestpytest提供的一个特殊的文件,用于存放fixture。在一个项目,如果有多个测试用例需要使用同一个fixture,那么我们可以将这个fixture放到conftest.py,这样所有的测试用例都可以使用这个fixture了。 下面是一个使用conftest的例子: 在conftest.py定义一个setup_database的fixture: ```python import pytest @pytest.fixture def setup_database(): # 连接数据库 yield # 断开连接 ``` 在测试用例使用这个fixture: ```python def test_something(setup_database): # 使用数据库进行测试 ``` 这样,我们就可以在测试用例使用setup_database这个fixture了,不需要重复写连接和断开数据库的代码。 总之,fixture和conftestpytest非常有用的工具,可以帮助我们在测试用例执行前后做一些准备和收尾工作,避免重复写相同的代码。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 43
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

敲代码敲到头发茂密

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值