上一篇我们介绍了Pytest的调用方式,这一篇我们将介绍 Pytest 的核心知识点fixture
fixture 是一个函数。
fixtures 的目的是提供一个固定的基线,使测试可以在此基础上可靠地、重复地执行, 是不是很晦涩难懂,用大家能理解的话来说即测试用例执行的环境准备和清理,在unittest 里即指 setup/teardown/setupClass/teardownClas
首先 明确一点,把一个函数定义为fixture 很简单,在函数申明前加 @pytest.fixture即可, 表示该函数为测试环境数据的准备和清理。
@pytest.fixturdef func(): pass
但要注意的是,在pytest中,环境准备和环境清理是完全放在一起的。在unittest中,它是两个都分开的,一个是setUp,一个是tearDown,我们会定义两个函数。 而在pytest中,只要一个函数就可以了(这个函数使用yield关键字,yield 关键字后面的代码,就是环境清理的代码,即测试用例执行完成后会执行的代码)。
fixture可以在当前的文件中来定义(私有化),也可以额外的去定义(公有化)。
前置和后置定义在特殊的文件当中,以后谁想要用,就直接调用就好了。一般调用函数,需要引进来才能调用,但是在pytest当中不需要。直接用个装饰器引用下就可以了,完全不需要引用这个文件。
那如何实现公有化方式呢? 在TeatCase目录下,新建一个Python文件,文件名固定是:conftest.py。这个文件就是公有文件,必须和测试用例放在一起,和测试用例文件是同级。
我们知道,装饰器也是函数,也能有参数。并且,这个fixture也有参数, 第一个参数是scope,scope就是会话级、模块级、类级、函数级。代表它的作用域,默认是function。什么是function?function是指单个的测试用例,也就是每一个测试用例。fixture剩下的一些参数可以暂时不用管。
如果未指定,则默认为 是 function 则对应了 unittest 中的 setUp/tearDown ,定义为function级别,则只要在测试用例的参数中使用了fixture函数名,则就会在测试用例的之前和之后执行fixture对应的操作 先来演示下:testcase/conftest.py
import pytest@pytest.fixture() ---》 等同于 @pytest.fixture(scope='function')def func(): print('这是函数前调用') yield print('这是函数后调用')
testcase/test_222.py
def testa(func): print('testa') assert 1def testc(): print('testc') assert 1def testb(func): print('testb') assert 1
执行命令 pytest -s -v
: 结果如下:
这是函数前调用testa.这是函数后调用testc.这是函数前调用testb.这是函数后调用
可以看出 testc() 没有接受func参数,所以 fixture 没有应用到这个函数上,而其他的函数的参数是我们定义的fixture,所以适用到这些函数上。
fixture的scope值还可以是class,此时则fixture定义的动作就会在测试类class的所有用例之前和之后运行,这里需要注意两点
•测试类中只要有一个测试用例的参数中使用了class级别的fixture,则在整个测试类的所有测试用例之前都会去执行fixture定义的动作,以及此测试类的所有用例结束后同样要运行fixture指定的动作•如果在类外的函数中去使用class级别的fixture,则此时在测试类外每个测试用例中,fixture跟上一节讲的function级别的fixture作用是一致的,即在类外的函数中弱引用了fixture,则在此函数之前和之后同样去执行fixture定义的对应的操作
示例如下:conftest.py
import pytest@pytest.fixture(scope="class")def func(): print("\nin fixture before testcase......") yield print("in fixture after testcase......")
同级目录 test_1.py
class TestExample: def test_01(self,func): print("in inner class test_01") def test_02(self,func): print("in inner class test_02") def test_03(self): print("\nin inner class test_03")
执行结果如下:
test_py/test_1.py in fixture before testcase......in inner class test_01.in inner class test_02.in inner class test_03.in fixture after testcase......
再演示类外函数 test_1.py
def test_01(func): print("in outer class test_01")def test_02(func): print("in outer class test_02")def test_03(): print("\nin outer class test_03")class TestExample: def test_01(self,func): print("in inner class test_01") def test_02(self,func): print("in inner class test_02") def test_03(self): print("\nin inner class test_03")
类外函数的结果和func级别一样!这边为节约篇幅就不演示给大家了。剩余的模块级 和 socpe 级别 大家可以去尝试下!
当fixture的scope定义为module时,只要当前文件中有一个测试用例使用了fixture,不管这个用例是在类外,还是在类中,都会在当前文件(模块)的所有测试用例执行之前去执行fixture定义的行为以及当前文件的所有用例结束之后同样去执行fixture定义的对应操作。示例如下: conftest.py
import pytest@pytest.fixture(scope="module")def func(): print("\nin fixture before testcase......") yield print("in fixture after testcase......")
测试上面的 test_1.py 文件,运行结果如下:
in fixture before testcase......in outer class test_01.in outer class test_02.in outer class test_03.in inner class test_01.in inner class test_02.in inner class test_03.in fixture after testcase......
会话级这边就不做演示了,大家有兴趣的话可以自己实践下。
上面的示例都是把 fixture 函数作为入参传入,fixture的第二种调用方式就是使用@pytest.mark.usefixtures的方式,如果有叠加调用,则先执行的需要放到下面 在test_example.py文件中编写如下代码 如下
@pytest.mark.usefixtures("func1")def test_01(): print("in test_01")@pytest.mark.usefixtures("func2")@pytest.mark.usefixtures("func1")def test_02(): print("in test_02")
运行效果都是一样的,有兴趣的同学可以自己实践下。