这里写自定义目录标题
1前言
unittest中执行用例前后有setup,teardown操作,pytest中有fixture且比unittest更加灵活,
fixture具有明确的名称,并通过在测试函数、模块、类或整个项目中声明它们的使用来激活。
fixture是以模块化的方式实现的,因为每个fixture名称都会触发fixture函数,其本身也可以使用其他fixture。
fixture管理从简单的单元扩展到复杂的函数测试,允许根据配置和组件选项参数化fixture和测试,或者在函数、类、模块或整个测试会话范围内重复使用fixture。
2 fixture作用域
function:默认值,覆盖测试用例
class:测试类
module:整个py文件
session:夹的是收集到的所有测试用例
3 具体使用
3.1function级别
3.1.1代码实现
import pytest
@pytest.fixture(scope='function')
def init():
print("开始执行测试用例")
yield
print("结束执行测试用例")
class TestCase:
@pytest.mark.usefixtures("init")
def test_aa(self):
print("i am test_aa")
assert 1==1
def test_bb(self):
print("i am test_bb")
assert 2 == 2
if __name__ =="__main__":
pytest.main(["-s","-v"])
其中yield前是执行用例前所需要执行的步骤,yield后是执行用例后所需要执行的步骤,如果有返回值,则是yield 返回值1,返回值2,多个返回值的话返回的是个元组
3.1.2返回结果
function.py [100%]
============================== 2 passed in 0.05s ==============================开始执行测试用例
.i am test_aa
结束执行测试用例
.i am test_bb
只有执行test_aa测试用例时执行了init方法
3.2 clsss级别
3.2.1代码实现
import pytest
@pytest.fixture(scope='class')
def init():
print("开始执行测试用例")
a,b=1,2
yield a,b
print("结束执行测试用例")
class TestCase:
def test_aa(self,init):
print("i am test_aa")
assert init[0]==1
def test_bb(self,init):
print("i am test_bb")
assert init[1] == 2
if __name__ =="__main__":
pytest.main(["-s","-v"])
3.2.2返回结果
fixture_class.py 开始执行测试用例
.i am test_aa
.i am test_bb
结束执行测试用例
[100%]
============================== 2 passed in 0.08s ==============================
Process finished with exit code 0
即使所有的用例都使用了init方法,但只是在class执行前执行了init前置步骤,class执行后执行了init后置步骤
如果fixture没有返回结果,可以使用如下方法
@pytest.mark.usefixtures("init")
class TestCase:
def test_aa(self):
print("i am test_aa")
assert 1==1
def test_bb(self):
print("i am test_bb")
assert 2 == 2
if __name__ =="__main__":
pytest.main(["-s","-v"])
3.3 moudle级别
整个py文件
3.3.1 代码实现
import pytest
@pytest.fixture(scope='module')
def init():
print("开始执行测试用例")
a,b=1,2
yield a,b
print("结束执行测试用例")
@pytest.mark.usefixtures("init")
class TestCase:
def test_aa(self):
print("i am test_aa")
assert 1==1
def test_bb(self):
print("i am test_bb")
assert 2 == 2
def test_cc():
print("i am test_cc")
assert 1 == 1
if __name__ =="__main__":
pytest.main(["-s","-v"])
3.3.2 返回结果
fixture_module.py 开始执行测试用例
.i am test_aa
.i am test_bb
.i am test_cc
结束执行测试用例
[100%]
============================== 3 passed in 0.08s ==============================
Process finished with exit code 0
在整个py文件前执行了前置步骤,py文件执行完成后执行了后置步骤
3.4 session级别
fixture为session级别是可以跨.py模块调用的,也就是当我们有多个.py文件的用例的时候,如果多个用例只需调用一次fixture,那就可以设置为scope=“session”,并且写到conftest.py文件里。
3.4.1 代码实现
代码目录
conftest.py文件代码为
import pytest
@pytest.fixture(scope='session',autouse=True)
def init():
print("开始执行测试用例")
yield
print("结束执行测试用例")
test_fixture_session.py文件代码
autouse是自动调用,即收集到的所有用例前都会执行
test_fixture_session.py文件代码
class TestCase:
def test_aa(self):
print("i am test_aa")
assert 1==1
def test_bb(self):
print("i am test_bb")
assert 2 == 2
test_fixture_session1.py文件代码
def test_cc():
print("i am test_cc")
assert 1 == 1
runall.py文件代码为
import pytest
pytest.main(["-s","-v","test_fixture_session.py","test_fixure_session1.py"])
执行runall.py
3.4.2 返回结果
collecting ... collected 3 items
test_fixture_session.py::TestCase::test_aa 开始执行测试用例
i am test_aa
PASSED
test_fixture_session.py::TestCase::test_bb i am test_bb
PASSED
test_fixure_session1.py::test_cc i am test_cc
PASSED结束执行测试用例
============================== 3 passed in 0.04s ==============================
Process finished with exit code 0
两个脚本执行前调用了init方法,输出开始执行测试用例,执行后输出结束执行测试用例
4 调用方法
从上面的例子中可以看出
如果需要使用fixture的返回值,那一定要传参,可以不用@pytest.mark.usefixtures("")
如果不需要使用fixture的返回值,一定要用@pytest.mark.usefixtures("")
5 源码解析
fixture源码详解
fixture(scope=‘function’,params=None,autouse=False,ids=None,name=None):
scope:有四个级别参数"function"(默认),“class”,“module”,“session”
params:一个可选的参数列表,它将导致多个参数调用fixture功能和所有测试使用它。
autouse:如果True,则为所有测试激活fixture func可以看到它。如果为False则显示需要参考来激活fixture
ids:每个字符串id的列表,每个字符串对应于params这样他们就是测试ID的一部分。如果没有提供ID它们将从params自动生成
name:fixture的名称。这默认为装饰函数的名称。如果fixture在定义它的统一模块中使用,夹具的功能名称将被请求夹具的功能arg遮蔽,解决这个问题的一种方法时将装饰函数命令"fixture_“然后使用”@pytest.fixture(name=’’)"。