pytest单元测试框架(三)-- fixture
前言
fixture是pytest特有的功能,它用pytest.fixture标识,定义在函数前面。在编写测试函数的时候,可以将函数名称作为传入参数,将函数的返回值作为测试函数的传入参数。
我们可以把fixture看做是资源,在你的测试用例执行之前需要去配置这些资源,执行完后需要去释资源。
fixture还提供了参数化功能,根据配置和不同组件来选择不同的参数。主要目的是为了提供一种可靠和可重复性的手段去运行那些最基本的测试内容。
fixture用途
-
做测试前后的初始化设置,如测试数据准备,连接数据库,打开浏览器等这些操作都可以使用fixture来实现
-
测试用例的前置条件可以使用fixture实现
-
支持经典的xunit fixture ,像unittest使用的setup和teardown
-
fixture可以实现unittest不能实现的功能,比如unittest中的测试用例和测试用例之间是无法传递参数和数据的,但是fixture却可以解决这个问题
firture相对于setup和teardown的优势
- 命名方式灵活,不局限于setup和teardown这几个命名
- conftest.py 配置里可以实现数据共享,不需要import就能自动找到一些配置
- 参数scope=‘module’ 可以实现多个.py跨文件共享前置,每一个.py文件调用一次
- scope=“session” 可以实现多个.py跨文件使用一个session来完成多个用例
def fixture(scope="function",params=None,autouse=False,ids=None,name=None):
'''
arg scope:有四个级别参数,function(默认)、class、module、session
arg params:可选参数,它将导致多个参数调用fixture功能和所有测试使用它
:arg ids: 每个字符串id的列表,每个字符串对应于params 这样他们就是测试ID的一部分。 如果没有提供ID它们将从params自动生成
:arg name: fixture的名称。 这默认为装饰函数的名称。 如果fixture在定义它的同一模块中使用,夹具的功能名称将被请求夹具的功能arg遮蔽; 解决这个问题的一种方法是将装饰函数命名 “fixture_ <fixturename>”然后使用”@ pytest.fixture(name ='<fixturename>')“”。
'''
fixtures可以选择使用yield语句为测试函数提供它们的值,而不是return。 在这种情况下,yield语句之后的代码块作为拆卸代码执行,而不管测试结果如何。fixture功能必须只产生一次
yield执行teardown
fixture里面的teardown用yield执行
@python.fixture(scope= = "module")
def open():
print("打开浏览器,且打开百度首页")
yield
print("执行tesrdown")
print("关闭浏览器")
def test_01(open):
print("测试1,搜索Python")
def test_02(open):
print("测试2,搜索")
'''
运行结果:
打开浏览器,且打开百度首页
测试1,搜索Python
测试2,搜索
执行teardown
关闭浏览器
'''
fixture当做参数传入
定义fixture跟定义普通函数差不多,唯一区别就是在函数上加个装饰器@pytest.fixture(),fixture明明不要以test开头,跟用例区分开,fixture是有返回值的,没有返回值默认为None,用例函数调用fixture的返回值,就是把fixture的函数名称当做变量名称
1、scope=“function”
import pytest
@pytest.fixture() #默认scope='function'
def demo():
a = 'hello'
print('demo被调用成功')
return a
def test1(demo):
assert demo == 'hello'
def test2():
print('test2不需要调用demo')
`
'''
# 输出
============================= test session starts =============================
platform win32 -- Python 3.7.0, pytest-5.3.1, py-1.8.0, pluggy-0.13.1 -- D:\python\Python\Python37\python.exe
cachedir: .pytest_cache
rootdir: D:\python\Python\project\youyou_class\study
collecting ... collected 2 items
day01_07_fixture.py::test1 demo被调用成功
PASSED [ 50%]
day01_07_fixture.py::test2 PASSED [100%]test2不需要调用demo
============================== 2 passed in 0.01s ==============================
Process finished with exit code 0
'''
补充:error和failed区别
测试结果一般有三种:passed、failed、error(skip的用例除外)
如果在test_用例里面的断言失败,就是failed
如果是在fixture里面断言失败了,那就是error
2、scope=“class”
fixture为class级别的时候,如果一个class里面有多个用例,尽管都调用了此fixture,那么此fixture只在该class里所有用例开始前执行一次。
import pytest
@pytest.fixture(scope='class')
def first():
a = 'hello'
print('scope为class级别,在类运行前执行一次')
return a
class TestCase():
def test1(self, first):
assert first == 'hello'
def test2(self, first):
print('first--->',first)
'''
结果:
============================= test session starts =============================
platform win32 -- Python 3.7.0, pytest-5.3.1, py-1.8.0, pluggy-0.13.1 -- D:\python\Python\Python37\python.exe
cachedir: .pytest_cache
rootdir: D:\python\Python\project\youyou_class\study
collecting ... collected 2 items
day01_07_fixture.py::TestCase::test1 scope为class级别,在类运行前执行一次
PASSED [ 50%]
day01_07_fixture.py::TestCase::test2 PASSED [100%]first---> hello
============================== 2 passed in 0.01s ==============================
Process finished with exit code 0
'''
3、scope=“module”
fixture为module级别时,在当前.py脚本里面所有用例开始前只执行一次
# fixture为module级别
@pytest.fixture(scope='module')
def first():
a = 'hello'
print('scope为module级别,在.py文件运行前执行一次')
return a
def test1(first):
assert first == 'hello'
def test2( first):
print('first--->', first)
'''
结果:
============================= test session starts =============================
platform win32 -- Python 3.7.0, pytest-5.3.1, py-1.8.0, pluggy-0.13.1 -- D:\python\Python\Python37\python.exe
cachedir: .pytest_cache
rootdir: D:\python\Python\project\youyou_class\study
collecting ... collected 2 items
day01_07_fixture.py::test1 scope为module级别,在.py文件运行前执行一次
PASSED [ 50%]
day01_07_fixture.py::test2 PASSED [100%]first---> hello
============================== 2 passed in 0.01s ==============================
Process finished with exit code 0
'''
4、scope=“session”
fixture为session级别是可以跨.py模块调用的,也就是当我们有多个.py文件的用例时候,如果多个用例只需调用一次fixture,那就可以设置为scope=“session”,并且写到conftest.py文件里
conftest.py配置
如果有多个.py文件都需要调用fixture,就不能写到用例里面去了,应该写一个配置文件,单独管理一些预置的操作场景,pytest会默认读取conftest.py里面的配置
conftest.py配置需要以下几点:
- conftest.py配置脚本名称是固定的,不能更改名称
- conftest.py与运行的用例要在同一个pakage下,并且有__init__.py文件
- 不需要import导入conftest.py,pytest用例会自动查找
-
fixture之autouse
平常写自动化用例会写一些前置的 fixture 操作,用例需要用到就直接传该函数的参数名称就行了。当用例很多的时候,每次都传返个参数,会比较麻烦。
fixture 里面有个参数 autouse,默讣是 Fasle 没开启的,可以设置为True 开启自动使用 fixture 功能,返样用例就丌用每次都去传参了,默认调用前置函数