fixture在pytest中是用来实现setup和teardown的方法,是在测试用例执行前后执行的函数,当有需要在测试用例执行前或执行后执行某些动作的场景时使用fixture来处理
一、fixture的调用方式:
fixture有三种调用方式
1、函数或类直接将fixture的函数名作为参数传入,调用多个用逗号隔开
import pytest
@pytest.fixture()
def login():
print '登录'
@pytest.fixture()
def start():
print '开始'
class TestIndex():
def test_myself(self,login,start):
print '示例'
运行结果:
2、使用装饰器@pytest.mark.usefixture()修饰
调用多个时,可以只修饰一次,用逗号分割fixture函数名
import pytest
@pytest.fixture()
def login():
print '登录'
@pytest.fixture()
def start():
print '开始'
class TestIndex():
@pytest.mark.usefixtures('login','start')
def test_myself(self):
print '示例'
运行结果:
也可以修饰多个,需要注意的是执行顺序是从下往上,有执行顺序要求时想先执行的要往下写
import pytest
@pytest.fixture()
def login():
print '登录'
@pytest.fixture()
def start():
print '开始'
class TestIndex():
@pytest.mark.usefixtures('login')
@pytest.mark.usefixtures('start')
def test_myself(self):
print '示例'
运行结果:
3、@pytest.fixture(autouse=True)自动调用,范围跟着scope走
import pytest
@pytest.fixture(autouse=True,scope='function')
def start():
print '开始'
class TestIndex():
def test_myself(self):
print '示例'
def test_class(self):
print '示例1'
运行结果:
可以看到函数、类都没有实际调用fixture,是自动调用的,作用范围是fixture设置的scope范围
4、使用装饰器@pytest.mark.parametrize(argnames=fixture函数名,indirect=True)
import pytest
@pytest.fixture()
def login():
print '登录'
@pytest.fixture()
def start():
print '开始'
class TestIndex():
@pytest.mark.parametrize('login,start',[('a','b')],indirect=True)
def test_myself(self,login,start):
print '示例'
运行结果:
这种调用方式是当你需要用fixture处理一些数据并返回一个返回值时使用,如果只是单纯的调用不推荐用这种方式
二、fixture参数介绍:
1、scope
fixture的作用域,fixture有四个作用域分别为session(会话级)、module(模块级)、class(类级)、function(函数级),作用域都是从开始引用fixture的位置开始
接下来从低到高依次说明:
代码先放在这里:
import pytest
@pytest.fixture(autouse=True,scope='function')
def login():
print '登录'
class TestIndex():
def test_myself(self):
print '示例'
def test_class(self):
print '示例1'
class TestIn():
def test_myself(self):
print '示例2'
1-1、function:
引用了fixture的函数都会执行一次fixture
范围是function,看到每个函数都执行了一次fixture
1-2、class
引用了fixture的类,在整个类只执行一次
@pytest.fixture(autouse=True,scope='class') #scope范围为class
每个class执行了一次
1-3、module
引用了fixture的模块,在整个模块只执行一次
@pytest.fixture(autouse=True,scope='module') #scope范围为module
一个文件只执行了一次
1-4、session
引用了fixture的会话,是指当前运行的整个项目,只执行一次
2、ids
用例标识ID,与params配合使用,一一对应
3、params
此参数是fixture的可选形参,支持传入列表,默认为None
每个params值fixture都会调用一次,类似for循环,与@pytest.mark.parametrize()的argvalues用法一致
可与ids一起使用,类似@pytest.mark.parametrize()的argvalues和argnames的关系
params在fixture中的使用要用pytest自带的request来调用:request.param
import pytest
@pytest.fixture(params=['张三'])
def login(request):
user = request.param # 使用pytest自带的request.param来调用fixture的params
print user
class TestIndex():
def test_myself(self,login):
print '示例'
运行结果:
4、name
fixture的重命名,若使用name重命名后,则调用fixture必须使用新的命名,否则报错
import pytest
@pytest.fixture(name='start')
def login():
print '登录'
class TestIndex():
def test_myself(self,start): # 这里调用必须使用新命名
print '示例'
运行结果:
import pytest
@pytest.fixture(name='start')
def login():
print '登录'
class TestIndex():
def test_myself(self,login): # 如果不使用新命名,就会报错
print '示例'
运行结果:
5、autouse
默认为False,若设置为True,则以scope的作用域为执行单位,自动调用fixture
具体前面有说明,这里不再复述
三、在fixture中前置后置方法用yield关键字区分
1、写在yield前面的程序为前置方法,前置会在执行测试用例之前执行,只实现前置时可省略yield
import pytest
@pytest.fixture()
def setup():
print '前置执行' # 此处只前置,省略yield
class TestIndex():
def test_myself(self,setup):
print '用例'
运行结果:
2、写在yield后面的程序为后置方法,后置会在测试用例执行结束后执行
import pytest
@pytest.fixture()
def setup():
yield
print '后置执行'
class TestIndex():
def test_myself(self,setup):
print '用例'
运行结果:
3、若有返回值,若需实现后置则必需有yield关键字,否则yield或return都可以
yield返回:
import pytest
@pytest.fixture()
def setup():
msg = '用例'
yield msg
print '后置执行'
class TestIndex():
def test_myself(self,setup):
print setup
运行结果:
return返回:
import pytest
@pytest.fixture()
def setup():
print '前置执行'
msg = '用例'
return msg
class TestIndex():
def test_myself(self,setup):
print setup
运行结果:
四、conftest.py
这个文件是pytest的配置文件,不需要import导入,pytest会自动识别,可以创建在根目录,也可以创建在用例目录下,建在哪个目录下它的作用范围就是哪个目录,需要注意conftest.py一定要与需要调用它的用例文件在同级或上级目录下,否则在下级或与用例所在目录同级的其他目录下是不生效的
该文件主要存放fixture,统一管理前置后置条件
目录层级:
package
testcase
test_index.py
conftest.py
conftest.py
import pytest
@pytest.fixture()
def setup():
print '前置执行'
msg = '用例'
return msg
test_index.py
class TestIndex():
def test_myself(self,setup):
print setup
运行结果:
fixture函数命名建议不要test_开头,与测试用例区分开
五、pytest搜索fixture的顺序
1、优先搜索测试函数所在模块
2、然后搜索模块所在目录下的conftest.py
3、找不到在继续逐层向上层搜索conftest.py
这里顺便提一下笔者在刚接触pytest的fixture时曾遇到一个坑,那个时候是从unittest换到pytest,当时因为知道pytest与unittest可以兼容,所以就没有去掉unittest的代码,而是在其基础上使用pytest,后来在用到fixture的时候就发现fixture不能正确使用,只有写在同一个文件下才可以调用fixture,而且怎么都拿不到fixture的返回值,fixture的大部分实现都做不到,后来查阅资料发现是因为当中混杂了unittest导致的,后来把unittest全部去掉就可以正常使用fixture了