pytest系列文章一共有四篇,本文为第三篇。
公众号:梦无矶的测试开发之路,回复pytest可以领取对应资料
本章知识点
示列代码
使用装饰器的方式,scope参数是代表指定作用域的
@pytest.fixture(scope='function')
def test_01(self):
print("test001")
源码分析
def fixture( # noqa: F811
fixture_function: Optional[FixtureFunction] = None,
*,
scope: "Union[_ScopeName, Callable[[str, Config], _ScopeName]]" = "function",
params: Optional[Iterable[object]] = None,
autouse: bool = False,
ids: Optional[
Union[Sequence[Optional[object]], Callable[[Any], Optional[object]]]
] = None,
name: Optional[str] = None,
) -> Union[FixtureFunctionMarker, FixtureFunction]:
可以简化为如下:
@pytest.fixture(scope="", params="", autouse="", ids="", name="")
scope:表示的是@pytest.fixtur标记方法的作用域,function(默认),class,module,package/session
params:可迭代参数,支持列表[],元组(),字典列表[{},{},{}],字典元组({}.{},{})
autouse=True:自动执行,默认为False,不会自动执行,需要手动调用
ids:当使用params参数化时,给每一个值设置一个变量名,用的少
name:给被@pytest.fixtur标记的方法取一个别名
scope参数为session:所有测试.py文件执行前执行一次
scope参数为module:每一个测试.py文件执行前都会执行一次conftest文件中的fixture
scope参数为class:每一个测试文件中的测试类执行前都会执行一次conftest文件中的
scope参数为function:所有文件的测试用例执行前都会执行一次conftest文件中的fixture
四个作用域
1、测试函数 function
2、测试类 class
3、测试模块 module
4、测试会话 session
默认为function
源码查看
:param scope:
The scope for which this fixture is shared; one of ``"function"``
(default), ``"class"``, ``"module"``, ``"package"`` or ``"session"``.
This parameter may also be a callable which receives ``(fixture_name, config)``
as parameters, and must return a ``str`` with one of the values mentioned above.
See :ref:`dynamic scope` in the docs for more information.
① 只需要在用例代码的参数中加入前置方法名即可完成前置操作
示列代码一:
class Test001():
@pytest.fixture(scope='function')
def beferFunction(self):
print("fixture的function")
@pytest.fixture(scope='class')
def beferClass(self):
print("fixture的class")
@pytest.fixture(scope='module')
def beferModule(self):
print("fixture的module")
def test_04(self,beferFunction,beferClass,beferModule):
print("测试用例004")
执行结果
============================= test session starts =============================
collecting ... collected 1 item
test_001.py::Test001::test_04 fixture的module
fixture的class
fixture的function
PASSED [100%]测试用例004
============================== 1 passed in 0.03s ==============================
执行顺序:module --> class --> function --> 用例
类级别的前后置,一定要写到第一个用例上, 写在最后一个上的话,执行时不会检测到有类级别前置,所以不会执行。检测到 有类级别前置,才会执行;
示列代码二:
② 使用@pytest.mark.usefixtures(“前/后置函数名”)
import pytest
@pytest.fixture(scope="function")
def fixture_fun():
print("function级别的前置操作")
yield
print("function级别的后置操作")
@pytest.mark.usefixtures("fixture_fun")
def test_001():
print("我是用例1111111")
运行结果
============================= test session starts =============================
collecting ... collected 1 item
test_001.py::test_001 function级别的前置操作
PASSED [100%]我是用例1111111
function级别的后置操作
============================== 1 passed in 0.01s ==============================
使用yield关键字实现后置操作
示列代码:
class Test001():
@pytest.fixture(scope='function')
def beferFunction(self):
print("fixture的function前置操作")
yield
print("fixture的function后置操作")
def test_001(self,beferFunction):
print("测试用例001")
运行结果:
============================= test session starts =============================
collecting ... collected 1 item
test_002.py::Test001::test_001 fixture的function前置操作
PASSED [100%]测试用例001
fixture的function后置操作
============================== 1 passed in 0.01s ==============================
其他级别前后置操作同理。
1、如果希望某个测试类下所有的方法都执行function级别的前后置方法,在测试类前使用@pytest.fixture(scope=‘function’)即可。
2、有多个同类型的scope叠加使用,从下至上依次执行。
# 传递
yield 返回值
# 接收
# 以fixture函数名作为用例参数,用例参数接收返回值,可以有多个
示列代码:
import pytest
@pytest.fixture(scope="function")
def func01():
print("函数级别的前置")
yield "返回值1",100
print("函数级别的后置")
@pytest.mark.usefixtures("func01")
def test001(func01): # 参数 func01 = 函数名叫做func01的返回值
print(f"测试用例test001,接收到的参数为:{func01}")
运行结果
============================= test session starts =============================
collecting ... collected 1 item
test_fixture前置数据传递.py::test001 函数级别的前置
PASSED [100%]测试用例test001,接收到的参数为:('返回值1', 100)
函数级别的后置
============================== 1 passed in 0.06s ==============================
通过conftest.py文件实现共享fixture,文件名固定为conftest.py
,不可更改
用处:在不同的py文件中使用同一个fixture函数
优先级:就近原则!
共享范围:当前conftest.py所在目录下的所有用例共享,包括子文件夹
conftest.py,是可以创建多个在不同的包下,可以层级创建的。
conftest.py需要和运行的用例放到同一层,不需要用import导入操作
所有同目录测试文件运行前都会执行conftest.py文件
新建如下目录结构:
在conftest.py
文件中编写如下代码:
# -*- coding: utf-8 -*-
'''
@Time : 2023/2/15 11:51
@Author : Vincent.xiaozai
@Email : [email protected]
@File : conftest.py
'''
__author__ = "梦无矶小仔"
'''
1、放的都是fixture
2、fixture可以对外共享
3、共享范围:
当前conftest.py所在目录下的所有用例共享,包括子文件夹
4、conftest.py,是可以创建多个在不同的包下,可以层级创建的。
5、优先级:就近原则!
'''
import pytest
@pytest.fixture(scope="function")
def func_fixture():
print("conftest.py下的func_fixture前置")
yield
print("conftest.py下的func_fixture后置")
@pytest.fixture(scope="function")
def func_fixture_01():
print("conftest.py下的func_fixture前置")
yield
print("conftest.py下的func_fixture后置")
@pytest.fixture(scope="class")
def class_fixture():
print("conftest.py下的class_fixture前置")
yield
print("conftest.py下的class_fixture后置")
@pytest.fixture(scope="module")
def module_fixture():
print("conftest.py下的module_fixture前置")
yield
print("conftest.py下的module_fixture后置")
@pytest.fixture(scope="function")
def func_fixture_param():
print("conftest.py下的func_fixture_param前置")
yield 1, 2, 3, 4, 5
print("conftest.py下的func_fixture_param后置")
在test_002.py
文件中直接使用conftest.py
文件中定义的fixture方法。
import pytest
@pytest.fixture(scope="function")
def func_fixture():
print("test_002.py下的func_fixture前置")
yield
print("test_002.py下的func_fixture后置")
class Test002():
def test_aa(self,func_fixture):
print("----运行了test_aa用例----")
def test_bb(self,func_fixture_01):
print("----运行了test_bb用例----")
def test_cc(self,class_fixture):
print("----运行了test_cc用例----")
def test_dd(self,func_fixture_param):
print(f"----运行了test_dd用例----参数:{func_fixture_param}")
@pytest.mark.usefixtures("func_fixture")
def test_ee(self):
print("----运行了test_ee用例----")
运行结果:
============================= test session starts =============================
collecting ... collected 5 items
test_002.py::Test002::test_aa test_002.py下的func_fixture前置
PASSED [ 20%]----运行了test_aa用例----
test_002.py下的func_fixture后置
test_002.py::Test002::test_bb conftest.py下的func_fixture前置
PASSED [ 40%]----运行了test_bb用例----
conftest.py下的func_fixture后置
test_002.py::Test002::test_cc conftest.py下的class_fixture前置
PASSED [ 60%]----运行了test_cc用例----
test_002.py::Test002::test_dd conftest.py下的func_fixture_param前置
PASSED [ 80%]----运行了test_dd用例----参数:(1, 2, 3, 4, 5)
conftest.py下的func_fixture_param后置
test_002.py::Test002::test_ee test_002.py下的func_fixture前置
PASSED [100%]----运行了test_ee用例----
test_002.py下的func_fixture后置
conftest.py下的class_fixture后置
============================== 5 passed in 0.02s ==============================
我们在两个文件中都有func_fixture
的fixture方法,运行发现,test_002.py
使用的是自己文件下的,而不是conftest
里面的,这很好的说明了一个就近原则。
@pytest.fixture
def func1():
print("func1的前置")
yield
print("func1的后置")
我有个需求,就是需要用到func1
,但是我要在此基础上新增一些内容。于是乎我造了一个func2
@pytest.fixture
def func2():
print("fun1的前置")
print("新增:func2的前置")
yield
print("新增:func2的后置")
print("func1的后置")
这样写会造成大量的代码冗余,有什么办法解决呢?这就需要用到我们继承的理念。
继承func1
并在内部执行func1
@pytest.fixture
def func3(func1):
print("新增:func3的前置")
yield func1
print("新增:func3的后置")
运行如下测试用例,输出结果就和调用func2
运行一致。
def test001(func3):
print("我是测试用例001")
### 运行结果如下 ###
============================= test session starts =============================
collecting ... collected 1 item
test_003_fixture嵌套.py::test001 func1的前置
新增:func3的前置
PASSED [100%]我是测试用例001
新增:func3的后置
func1的后置
============================== 1 passed in 0.01s ==============================
Process finished with exit code 0