pytest中使用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的参数autouse=True这样每个测试用例会自动调用fixture(其实这里说的不是很准确,因为还涉及到fixture的作用范围,那么我们这里默认是函数级别的,后面会具体说fixture的作用范围)
上述的实例默认都是函数级别的,所以测试函数只要调用了fixture,那么在测试函数执行前都会先指定fixture。说到作用范围就不得不说fixture 的第二个参数scope参数。
scope参数可以是session, module,class,function; 默认为function
@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 函数 只执行了一次
例子
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的参数化功能
@pytest.fixture(params=[1,2,3]) def data(request): return request.param def test_not2(data): print(f"测试数据:{data}") assert data <4
@pytest.fixture(scope="session") def login(): # yield 前面相当于 setup print("这里实现登录操作") token = "j;fdkafjadfa" # yield 相当于return yield # yield 后面相当于teardown操作 print("实现登出操作")执行结果