pytest的fixtures是使pytest在其他测试框架之上脱颖而出的独特核心功能之一,也是许多人使用pytest的原因。在pytest中,fixture指的是一种分离出“测试准备工作”和“测试结束收尾工作的代码的机制。
创建fixture
给函数增加一个@pytest.fixture()
装饰器,pytest就会把该函数作为一个fixture
。如果测试函数的形参中填写了fixture,pytest就会在测试函数运行之前调用这些fixtures。fixture可以用来执行通用的工作,也可以return数据给测试函数。
1 |
|
如上,test_func
函数形参中传入了名为func
的fixture
。pytest会在module
中查找名为func的函数。如果在module中找不到fixture,还会在conftest.py
中寻找。
通过confest.py共享fixtures
我们可以把fixture放在独立的文件中。但是,想要让所有的测试函数都能使用conftest.py
中的fixtures,则需要把文件放在所有测试函数文件的最上层目录。
尽管conftest.py是一个module
,但是不要手动import
它。它会被pytest自动识别并当作一个本地plugin
。(关于插件的内容后面进一步学习)目前,只要把conftest.py想象成一个使得我们可以在目录下放置所有测试函数使用的fixture
的地方即可。
用fixture实现setup和teardown功能
许多测试用例都有setup
和teardown
的部分,即测试环境准备和环境清理。通过在fixture中使用yield
关键字,可以很方便的实现setup和teardown。
1 |
|
yield前面的部分,是setup部分,会在测试函数前运行。yield后面的部分,是teardown部分,会在测试函数后运行。
使用–step-show跟踪fixture执行
在运行pytest时,添加--setup-show
选项后,能够在输出中观看到fixture执行过程。
1 |
|
如上,显示了fixtures的调用过程。
SETUP
和TAEADOWN
调用了fixture_func。
S表示
session域的fixture、
M表示
module域的fixture、
F表示
function域的fixture、
C表示
class`域的fixture。
使用fixture提供测试数据
fixture很适合用来提供测试数据。fixture可以return
任何数据类型。测试函数使用fixture函数名就能使用return
的数据。
1 |
|
fixture的嵌套
fixture函数的入参也可以填写fixture`,这出现了嵌套调用fixture的情况。
1 |
|
运行结果:
1 |
|
指定fixture的域
pytest.fixture()有个参数叫做scope
,用来控制fixture的作用级别。scope可选值为:
function
:作用于每个函数。setup部分在每个函数前运行,teardown部分在每个函数后运行。scope默认为function。class
:作用于每个类。无论类中有多少个函数声明了该fixture,只运行一次。module
:作用于每个模块。无论一个模块中有多少个函数或方法声明了该fixture,只运行一次。session
:作用一次会话(pytest任务)。在一次pytest任务中,该fixture只在启动和结束时运行一次。
通过pytest.mark.usefixtures指定fixtures
通过前文,我们了解到,要使用fixtures,可以把fixture函数名写到函数的入参中。不过,还有另一种方法可以使用fixture。
1 |
|
使用@pytest.mark.usefixtures()
装饰器也可以给函数指定fixture。注意,usefixtures()
函数里面填的不是函数名,而是函数名字符串。使用usefixtures()
和直接在形参中填写fixtures的方式没有区别。但是,使用usefixtures()方式,测试函数不能获取fixture函数的return
值。
当我们要给一个测试class中的所有测试方法使用相同的fixture,且不需要fixture的return值的时候,可以用@pytest.mark.usefixtures()
。
通过autouse参数让测试函数默认使用fixture
pytest.fixture()
有个autouse
参数。这个参数决定一个fixture是否是默认被使用的。设置autouse=True
则fixture默认被所有测试函数使用。autouse
默认值为False
。
1 |
|
使用pytest –setup-show 查看函数执行,发现SETUP
和TEARDOWN
都有fix_func1,但是断言是失败的,因为fix_func1的值不是1,而是一个函数对象。可能这是因为没有在test_func1函数的形参里定义fix_func1。
重命名fixture
pytest.fixture()有个name
参数,可以让我们重命名fixture。
1 |
|
参数化fixture
之前学习了使用@pytest.mark.parameterize(name,values,ids)
对测试函数进行参数化。其实fixture也可以实现参数化,需要用到@pytest.fixture()
函数中的params
参数。params参数接收一个list
,list中的一项就存放一组参数化数据。使用了这个fixture的测试函数会执行len(list)
次。
在fixture函数中使用request
这个内置fixture,可以获取params中的参数化数据。注意是request.param
,这里的param
没有s
。
1 |
|
使用pytest -v
运行上面的代码:
1 |
|
可以看到,执行了三次测试函数。
另外,@pytest.fixture()
类似@pytest.mark.parameterize()
也有一个ids
参数。作用也是一样的,可以参考之前的文章。补充一点,ids
可以接受一个字符串list,也可以接受一个函数名。这个函数是将每组参数化数据对象,转化为字符串的函数。
1 |
|
运行上面的代码:
1 |
|
至此,我们学习完了pytest.fixture()
的所有参数(name,scope,autouse,params,ids)~
两种参数化功能可以同时使用,效果是叠加的,M*N次。