最近在pytest中使用了很多装饰器觉得很好用,现在总结一下:
pytest.fixture
一、通过装饰器@pytest.fixture(),定义测试固件(test fixture)。
实现setup_xxx的功能:
import pytest
# 函数名自定义
# 此时,login函数是一个测试固件,相对于实现了setup_xxx的功能。
@pytest.fixture()
def login():
print('登录系统')
token = 'a1b23c'
return token
# 在测试函数里, 通过形参来声明要使用的测试固件。
def test1(login):
# 参数login的值是测试固件login函数的返回值
print('in test1: ', login)
print('测试1')
def test2(login):
print('in test2: ', login)
print('测试2')
实现teardown_xxx的功能
方法一:使用yield关键字
import pytest
# 此时,login函数是一个测试固件,相当于实现了setup_xxx&teardown_xxx的功能。
@pytest.fixture()
def login():
############# 以下的代码相当于setup部分 ###########
print('登录系统')
token = 'a1b23c'
yield token
############# 以下的代码相当于teardown部分 ###########
print('退出登录')
# 在测试函数里, 通过形参声明要使用的测试固件
def test1(login):
# login参数的值是测试固件函数的返回值
print('in test1: ', login)
print('测试1')
def test2(login):
print('in test2: ', login)
print('测试2')
执行结果:
登录系统
in test1: a1b23c
测试1
.退出登录
登录系统
in test2: a1b23c
测试2
.退出登录
方法二:使用request.addfinalizer()注册清理函数
import pytest
# login函数是一个测试固件,相当于实现了setup_xxx&teardown_xxx的功能
@pytest.fixture()
# 声明使用request测试固件
def login(request):
print('登录系统')
token = 'a1b23c'
# 定义一个清理函数, 清理函数向相当于teardown_xxx
def fin():
print('退出登录')
# 注册一个清理函数
request.addfinalizer(fin)
# 注册完清理函数后,如果在测试固件里抛出异常,只有清理函数照常执行
# 1 / 0
return token
def test1(login):
print('in test1: ', login)
print('测试1')
def test2(login):
print('in test2: ', login)
print('测试2')
可以定义和注册多个清理函数
import pytest
# login函数是一个测试固件,相当于实现了setup_xxx&teardown_xxx的功能
@pytest.fixture()
def login(request):
print('登录系统')
token = 'a1b23c'
def fin1():
print('退出登录1')
def fin2():
print('退出登录2')
# 执行完测试用例后,将按照注册顺序的相反顺序来调用(先fin2,后fin1)
request.addfinalizer(fin1)
request.addfinalizer(fin2)
return token
def test1(login):
print('in test1: ', login)
print('测试1')
def test2(login):
print('in test2: ', login)
print('测试2')
二、使用装饰器@pytest.fixture()的name参数,指定测试固件的名字。
import pytest
# 给测试固件重新命名为driver,如果不命名,默认login
@pytest.fixture(name = "driver")
def login():
print('登录系统')
token = 'a1b23c'
yield token
print('退出登录')
def test1(driver):
print('in test1: ', driver)
print('测试1')
def test2(driver):
print('in test2: ', driver)
print('测试2')
三、通过装饰器@pytest.fixture()的参数scope,设置测试固件的作用域(scope)
1、session > module > class > function
2、代码1
import pytest
# scope的值默认function
@pytest.fixture(scope='module')
def log():
print('开始测试')
yield
print('结束测试')
@pytest.fixture(scope='function')
def login():
print('登录系统')
yield
print('退出登录')
# 注意传参
def test1(log, login):
print('测试1')
def test2(log, login):
print('测试2')
执行结果:
setup_demo.py::test1 开始测试
登录系统
测试1
PASSED退出登录
setup_demo.py::test2 登录系统
测试2
PASSED退出登录
结束测试
代码2
import pytest
@pytest.fixture(scope='module')
def login_module():
print('开始测试_模块级别')
yield
print('结束测试_模块级别')
@pytest.fixture(scope='class')
def login_class():
print('登录系统_类级别')
yield
print('退出登录_类级别')
@pytest.fixture(scope='function')
def login_func():
print('登录系统_函数级别')
yield
print('退出登录_函数级别')
class TestFoo(object):
def test1(self, login_module, login_class, login_func):
print('测试1')
def test2(self, login_module, login_class, login_func):
print('测试2')
执行结果:
setup_demo.py::TestFoo::test1 开始测试_模块级别
登录系统_类级别
登录系统_函数级别
测试1
PASSED退出登录_函数级别
setup_demo.py::TestFoo::test2 登录系统_函数级别
测试2
PASSED退出登录_函数级别
退出登录_类级别
结束测试_模块级别
代码3-----演示session级别的测试固件
①创建一个python包session_demo
②来个test_1.py
def test_1_1(login):
print('test_1_1')
def test_1_2(login):
print('test_1_2')
③来个test_2.py
def test_2_1(login):
print('test_2_1')
def test_2_2(login):
print('test_2_2')
④再来个conftest.py(固定文件名)
import pytest
@pytest.fixture(scope='session')
def login():
print('登录系统')
⑤cd到session_demo,然后pytest -sv .
执行结果
test_1.py::test_1_1 登录系统
test_1_1
PASSED
test_1.py::test_1_2 test_1_2
PASSED
test_2.py::test_2_1 test_2_1
PASSED
test_2.py::test_2_2 test_2_2
PASSED
四、通过装饰器@pytest.fixture()的参数params,实现测试固件的参数化。
代码1
import pytest
@pytest.fixture(params=['tom', 'jack'])
def login(request):
print('%s登录' % request.param)
def test1(login):
print('执行测试1')
执行结果:
setup_demo.py::test1[tom] tom登录
执行测试1
PASSED
setup_demo.py::test1[jack] jack登录
执行测试1
PASSED
代码2
import pytest
@pytest.fixture(params=[('tom', '123'), ('jack', '1234')])
def login(request):
user = request.param[0]
passwd = request.param[1]
print('登录系统: 用户名%s, 密码%s' %(user, passwd))
def test1(login):
print('test 1')
执行结果:
# 没有指定参数ids,自动生成测试用例的id
conftest.py::test1[login0] 登录系统: 用户名tom, 密码123 # 测试用例的id是login0
test 1
PASSED
conftest.py::test1[login1] 登录系统: 用户名jack, 密码1234 # 测试用例的id是tlogin1
test 1
PASSED
可以通过装饰器@pytest.fixture()的参数ids,设置测试用例的id。
import pytest
@pytest.fixture(params=[('tom', '123'), ('jack', '1234')],
ids=['user_a', 'user_b']) # 这两个列表里,元素的数目要匹配
def login(request):
user = request.param[0]
passwd = request.param[1]
print('登录系统: 用户名%s, 密码%s' %(user, passwd))
def test1(login):
print('test 1')
执行结果:
conftest.py::test1[user_a] 登录系统: 用户名tom, 密码123
test 1
PASSED
conftest.py::test1[user_b] 登录系统: 用户名jack, 密码1234
test 1
PASSED
五、在项目里运用起来