fixture
pytest中使用fixture装饰器来装饰一个方法,被装饰的方法可以作为一个参数传到测试方法中,用于完成测试执行前的初始化,也可以返回数据给测试函数。
用法1:fixture作为函数参数
通常使用setup 和 teardown来进行资源的初始化。如果有这样一个场景,测试用例1和测试用例3需要依赖登录功能,测试用例2不需要依赖登录功能。这种场景setup,teardown无法实现,可以使用装饰器,加了这个装饰器的方法可以以参数的pytest fixture功能,在方法前面加个 @pytest.fixture形式传入到方法里面执行。
例如在登录的方法,加上 @pytest.fixture这个装饰器后,将这个用例方法名以参数的形式传到方法里,这个方法就会先执行这个登录方法,再去执行自身的用例步骤,如果有传入这个登录方法,就不执行登录操作,直接执行已有的步骤。
例子
import pytest
@pytest.fixture
def login():
print("这是一个登录方法")
return('jack','22')
@pytest.fixture()
def operate():
print("登录后的操作")
def test_1(login,operate):
print(login)
print("test1,需要登录")
def test_2():
print("test2,不需要登录")
def test_3():
print(login)
print("test3,需要登录")
在上面的代码中,测试case test1和case test3 分别增加login方法名作为参数,pytest会发现并调用pytest.fixture标记的login 功能
执行结果
test_fixture.py::test_1 这是一个登录方法
登录后的操作
PASSED [ 33%]('jack', '22')
test1,需要登录
test_fixture.py::test_2 PASSED [ 66%]test2,不需要登录
test_fixture.py::test_3 这是一个登录方法
PASSED [100%]('jack', '22')
test3,需要登录
test1 和test3 分别执行了login方法,test2 没有执行 这个方法
fixture使用的三种方式
- 如上文fixture注解下的函数方法名 直接作为测试用例的参数, def test_1(login,operate)
- 使用@pytest.mark.usefixtures('fixture')装饰器
- 使用autouse参数 @pytest.fixture(autouse=True)
指定fixture的参数autouse=True这样每个测试用例会自动调用fixture(其实这里说的不是很准确,因为还涉及到fixture的作用范围,那么我们这里默认是函数级别的,后面会具体说fixture的作用范围)
fixture 作用域 scope
上述的实例默认都是函数级别的,所以测试函数只要调用了fixture,那么在测试函数执行前都会先指定fixture。说到作用范围就不得不说fixture 的第二个参数scope参数。
scope参数可以是session, module,class,function; 默认为function
- session 会话级别(通常这个级别会结合conftest.py文件使用,所以后面说到conftest.py文件的时候再说)
- module 模块级别: 模块里所有的用例执行前执行一次module级别的fixture
- class 类级别 :每个类执行前都会执行一次class级别的fixture
- function :函数级别,每个测试用例执行前都会执行一次function级别的fixture
@pytest.fixture(scope='module', autouse=True)
def module_fixture():
print('我是module fixture')
@pytest.fixture(scope='class')
def class_fixture():
print('我是class fixture')
@pytest.fixture(scope='function', autouse=True)
def func_fixture():
print('我是function fixture')
执行普通测试方法:
def test_1():
print('\n 我是test1')
执行结果为: function 函数级别,每个测试方法前都会执行
我是function执行class 级别的case
执行结果为: function与class 作用域的函数 module 函数 只执行了一次
fixture实现 teardown
例子
import pytest
@pytest.fixture(scope="module")
def open():
print("打开浏览器")
yield
print("执行teardown")
print("关闭浏览器")
@pytest.mark.usefixtures("open")
def test_search1():
print("test_search")
raise NameError
pass
def test_search2(open):
print("test_search2")
pass
def test_search3(open):
print("test_search3")
pass
执行结果
从上面的执行结果可以看出,scope="module“与yield 结合 相当于step_module与teardown_module,通过yield 唤醒teardown 的执行,若用例出现一场,不影响后面的yield与后面的teardown执行
fixture 传递参数
测试过程若需要大量的测试数据,则可以使用fixture的参数化功能
@pytest.fixture(params=[1,2,3])
def data(request):
return request.param
def test_not2(data):
print(f"测试数据:{data}")
assert data <4
conftest.py 全局调用
- 可以跨.py文件调用,有多个.py文件调用时,可让conftest.py只调用了一次fixture,或调用多次fixture
- conftest.py与运行的用例要在同一个pakage下,并且有__init__.py文件
- 不需要import导入 conftest.py,pytest用例会自动识别该文件,放到项目的根目录下就可以全局目录调用了,如果放到某个package下,那就在改package内有效,可有多个conftest.py
- conftest.py配置脚本名称是固定的,不能改名称
- conftest.py文件不能被其他文件导入
- 所有同目录测试文件运行前都会执行conftest.py文件
@pytest.fixture(scope="session")
def login():
# yield 前面相当于 setup
print("这里实现登录操作")
token = "j;fdkafjadfa"
# yield 相当于return
yield
# yield 后面相当于teardown操作
print("实现登出操作")
执行结果