带你认识Pytest(三)

时间:2022-07-26
本文章向大家介绍带你认识Pytest(三),主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

前言

上一篇我们介绍了Pytest的调用方式,这一篇我们将介绍 Pytest 的核心知识点fixture

fixture

fixture 是一个函数。 fixtures 的目的是提供一个固定的基线,使测试可以在此基础上可靠地、重复地执行, 是不是很晦涩难懂,用大家能理解的话来说即测试用例执行的环境准备和清理,在unittest 里即指 setup/teardown/setupClass/teardownClas

定义fixture

首先 明确一点,把一个函数定义为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 函数级

如果未指定,则默认为 是 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")

运行效果都是一样的,有兴趣的同学可以自己实践下。