pytest夹具:fixture详解01
目录
一、定义
pytest框架的fixture测试夹具就相当于unittest框架的setup、teardown,但相对之下它的功能更加强大和灵活。
1、命名方式灵活,不限于unittest的setup、teardown
2、可以实现数据共享,多个模块跨文件共享前置后置
3、可以实现多个模块跨文件使用一个session来完成多个用例
4、可以实现unittest不能实现的功能,比如unittest中的测试用例和测试用例之间是无法传递参数和数据的,但是fixture却可以解决这个问题
二、fixture调用
使用@pytest.fixture()用于声明函数是处理前置后置的测试夹具函数,
方式一:将fixture名称作为参数传给测试用例,可以传多个fixture,按先后顺序执行
方式二:装饰器:@pytest.mark.usefixtures(fixture_name)
1、使用在类上,代表这个类所有测试用例都会调用这个fixture
2、在用例上,代表只有这个用例调用这个fixture
3、可以使用多个fixture,按先后顺序执行
4、如果fixture有返回值,用这个装饰器是无法获取到返回值的,也就无法给用例传递数据,只能用方法一
方式三:fixture设置autouse=True
自动调用,同样fixture有返回值时,无法获取返回值
import pytest
@pytest.fixture()
def fixture_a():
print("this is my fixture")
#plan 1
def test_plan_a(fixture_a):
print("this is plan a")
print("haaaaaaaaaa")
#plan 2
@pytest.mark.usefixtures("fixture_a")
def test_plan_b():
print("this is plan b")
print("haaaaaaaaaa")
输出结果:
rootdir: D:\pytest\learn01, configfile: pytest.ini
collected 2 items
test_sample.py this is my fixture
this is plan a
haaaaaaaaaa
.this is my fixture
this is plan b
haaaaaaaaaa
#plan 3
@pytest.fixture(autouse=True)
def fixture_a():
print("this is my fixture")
def test_plan_3():
print("this is plan c")
print("haaaaaaaaaa")
# 应用到类中
class TestClass:
def test_plan_d(self):
print("this is plan d")
print("haaaaaaaaaa")
def test_plan_e(self):
print("this is plan e")
print("haaaaaaaaaa")
输出结果:
test_sample.py this is my fixture
this is plan c
haaaaaaaaaa
.this is my fixture
this is plan d
haaaaaaaaaa
.this is my fixture
this is plan e
haaaaaaaaaa
三、fixture作用域
代码:@pytest.fixture(scope='作用范围')
,参数如下:
function
:默认作用域,每个测试用例都运行一次class
:每个测试类只执行一次module
:每个模块只执行一次package
:每个python包只执行一次session
:整个会话只执行一次,即运行项目时整个过程只执行一次
优先级:session > package > module > class > function,优先级高的会在低的fixture之前先实例化(在function范围,最先调用的一定是autouse)
import pytest,time
@pytest.fixture(scope='class')
def my_fixture():
print('前置条件,初始化列表')
l=[]
l.append(time.time)
yield l
print('后置条件,清空列表')
l=[]
class TestCase:
def test_case01(self,my_fixture):
l=my_fixture
print('first case')
print('列表长度为:')
print(len(l))
assert 1==1
def test_case02(self,my_fixture):
l=my_fixture
print('second case')
print('列表长度为:')
print(len(l))
assert 1==1
输出结果:
test_sample.py 前置条件,初始化列表
this is my fixture
first case
列表长度为:
1
.this is my fixture
second case
列表长度为:
1
.后置条件,清空列表
由此可以看出,整个类,值初始化了一次列表
四、conftest.py共享夹具函数
conftest特点:
1、可以跨.py文件调用,有多个.py文件调用时,可让conftest.py只调用了一次fixture,或调用多次fixture
2、conftest.py与运行的用例要在同一个pakage下,并且有init.py文件
3、不需要import导入 conftest.py,pytest用例会自动识别该文件,放到项目的根目录下就可以全局目录调用了,如果放到某个package下,那就在改package内有效,可有多个conftest.py
4、conftest.py配置脚本名称是固定的,不能改名称
5、conftest.py文件不能被其他文件导入
6、所有同目录测试文件运行前都会执行conftest.py文件。
conftest结合fixture的使用:
1、conftest中fixture的scope参数为session,所有测试.py文件执行前执行一次
2、conftest中fixture的scope参数为module,每一个测试.py文件执行前都会执行一次conftest文件中的fixture
3、conftest中fixture的scope参数为class,每一个测试文件中的测试类执行前都会执行一次conftest文件中的fixture
4、conftest中fixture的scope参数为function,所有文件的测试用例执行前都会执行一次conftest文件中的fixture
conftest应用场景:
1、每个接口需共用到的token
2、每个接口需共用到的测试用例数据
3、每个接口需共用到的配置信息
4、数据库的初始化连接、关闭
5、打开浏览器、关闭浏览器
示例
多个.py文件只调用一次fixture
# 根目录下conftest.py
import pytest
@pytest.fixture(scope='session')
def login_session():
print("初始化session")
session='123456789'
return session
#a目录下的test_a.py文件
import pytest
def test1(login_session):
session='123456789'
print('执行a目录下的test1方法,获取login_session:%s'%login_session)
assert session==login_session
#b目录下的test_sample.py文件
def test2(login_session):
session='123456789'
print('执行b目录下的test2方法,获取login_session:%s'%login_session)
assert session==login_session
输出结果:
D:\pytest\learn01>pytest -v -s a/test_a.py b/test_sample.py
========================================================================================== test session starts ===========================================================================================
platform win32 -- Python 3.7.3, pytest-6.2.4, py-1.10.0, pluggy-0.13.1 -- d:\python3.7\python\python3.exe
cachedir: .pytest_cache
rootdir: D:\pytest\learn01, configfile: pytest.ini
collected 2 items
a/test_a.py::test1 初始化session
执行a目录下的test1方法,获取login_session:123456789
PASSED
b/test_sample.py::test2 执行b目录下的test2方法,获取login_session:123456789
PASSED
五、夹具终止 / 执行 teardown 代码
pytest支持当夹具超出作用域时,执行特定夹具的清理代码。可以通过使用yield替换return,可以实现teardown的功能,所有在yield之后的代码将会执行清理工作。
# content of conftest.py
import smtplib
import pytest
@pytest.fixture(scope="module")
def smtp_connection():
smtp_connection = smtplib.SMTP("smtp.qq.com", 587, timeout=5)
yield smtp_connection # provide the fixture value
print("teardown smtp")
smtp_connection.close()
# content of test_c.py
def test_conn(smtp_connection):
response, msg = smtp_connection.ehlo()
assert response == 250
assert b"smtp.qq.com" in msg
assert 0 # for demo purposes
输出结果:
D:\pytest\learn01>pytest -v -s a/test_c.py
========================================================================================== test session starts ===========================================================================================
platform win32 -- Python 3.7.3, pytest-6.2.4, py-1.10.0, pluggy-0.13.1 -- d:\python3.7\python\python3.exe
cachedir: .pytest_cache
rootdir: D:\pytest\learn01, configfile: pytest.ini
collected 1 item
a/test_c.py::test_conn FAILEDteardown smtp
其他内容省略
可以看出,print 和 smtp.close()会在模块的最后一个用例执行完成之后执行,不管测试执行的状态如何。
也可以结合with 来使用yield:
import smtplib
import pytest
@pytest.fixture(scope="module")
def smtp_connection():
with smtplib.SMTP("smtp.qq.com", 587, timeout=5) as smtp_connection:
yield smtp_connection # provide the fixture value
需要注意的是,如果在setup的过程中(yield关键字之前)发生异常,teardown的代码就不会运行。另一个执行teardown代码的可选方法是利用上下文request对象的addfinalizer方法来注册一个结束方法。 下面是夹具使用 addfininalizer进行清理的方法:
import pytest
@pytest.fixture()
def myfixture(request):
print ("执行固件myfixture的前半部分")
def myteardown():
print("执行固件myfture的后半部分")
request.addfinalizer(myteardown)
class Test_Pytest():
def test_one(self,myfixture):
print("test_one方法执行" )
assert 1==1
def test_two(self):
print("test_two方法执行" )
assert "o" in "love"
def test_three(self):
print("test_three方法执行" )
assert 3-2==1
输出结果:
D:\pytest\learn01>pytest -s a/test_a.py
========================================================================================== test session starts ===========================================================================================
platform win32 -- Python 3.7.3, pytest-6.2.4, py-1.10.0, pluggy-0.13.1
rootdir: D:\pytest\learn01, configfile: pytest.ini
collected 3 items
a\test_a.py 执行固件myfixture的前半部分
test_one方法执行
.执行固件myfture的后半部分
test_two方法执行
.test_three方法执行
.