python测试(16)

fixture

fixture是指夹具(把用例夹在中间),它包括前置工作和后置工作,前置是用例代码的准备阶段,后置是用例执行之后的清理阶段,用例是放在前置代码和后置代码之间的

首先先定义一个fixture函数

unittest框架中前置函数名叫做setup,后置函数名叫做teardown

但是在**pytest框架中并没有这个规则,它的前置函数名和后置函数名都可以自取**

如果说前置函数名和后置函数名可以随便取的话,那么要如何和普通函数分辨呢?——答案就是:在函数名前面加一个@pytest.fixture这样说明这个就是一个夹具

而且前置代码和后置代码是放在同一个文件下,那么应该如何判断哪一部分是前置代码,哪一部分是后置代码呢?——答案就是使用yield关键字作为分割线,它之前的属于前置代码,它之后的属于后置代码

fixture夹具有几个作用域?

之前提到过用例被夹在前置代码和后置代码之中,那么这中间到底夹的是一个一个的测试函数还是测试类,测试模块或者是说测试会话呢?中间夹什么是可以自己去设置的,最后只要去调用一下就可以。它一共有四个作用域:function(测试函数)、class(测试类)、module(测试模块)、session(测试会话) PS:夹具的函数名没有要求,可以按照需求取

测试函数的执行结果模板:

前置函数…

一个函数执行

后置函数…

前置函数…

第二个函数执行

后置函数…

…(直到所有的函数执行完)

例如:

import pytest

@pytest.fixture
def go_try():
    print('我是前置代码')
    yield
    print('我是后置代码')

@pytest.mark.usefixtures('go_try')
def test_001_try():
    print('test new...')


@pytest.mark.usefixtures('go_try')
def test_002_try():
    print('test new1...')

@pytest.mark.usefixtures('go_try')
def test_003_try():
    print('test new2...')

运行结果:

python测试(16)_第1张图片

测试类的执行结果模板:

前置函数…

一个类执行

后置函数…

前置函数…

另一个类执行

后置函数…

…(直到所有的类执行完成)

例如:

import pytest

@pytest.fixture(scope='class')
def go_try():
    print('我是前置测试类代码')
    yield
    print('我是后置测试类代码')

@pytest.mark.usefixtures('go_try')
class Test_001_try:
    def test_001_try(self):
        print('test new...')

    def test_002_try(self):
        print('test new1...')

    def test_003_try(self):
        print('test new2...')


@pytest.mark.usefixtures('go_try')
class Test_002_try:
    def test_003_try(self):
        print('test new3...')

    def test_004_try(self):
        print('test new4...')

    def test_005_try(self):
        print('test new5...')

scope参数用来设置作用域

运行结果:

python测试(16)_第2张图片

测试函数的夹具初始化是:@pytest.fixture,然后里面加上函数。想要使用时前面加@pytest.mark.usefixtures('夹具函数名称')

测试类的夹具初始化是:@pytest.fixture(scope='class'),然后里面加上函数。想要使用时前面加@pytest.mark.usefixtures('夹具函数名称')

测试模块的夹具初始化是:@pytest.fixture(scope='module'),然后里面加上函数。想要使用时前面加@pytest.mark.usefixtures('夹具函数名称')

测试会话的夹具初始化是:@pytest.fixture(scope='session'),然后里面加上函数。想要使用时前面加@pytest.mark.usefixtures('夹具函数名称')

PS!!!补充一个特别重要的点:如果说想要使用夹具,要自己根据是否符合前置条件和后置条件,然后再主动加上@那一部分,不加是不会被夹进去的

例如:

import pytest

@pytest.fixture(scope='class')
def go_try():
    print('我是前置测试类代码')
    yield
    print('我是后置测试类代码')

@pytest.mark.usefixtures('go_try')
class Test_001_try:
    def test_001_try(self):
        print('test new...')

    def test_002_try(self):
        print('test new1...')

    def test_003_try(self):
        print('test new2...')



class Test_002_try:
    def test_003_try(self):
        print('test new3...')

    def test_004_try(self):
        print('test new4...')

    def test_005_try(self):
        print('test new5...')

前一段代码中第一个类使用了夹具,第二个类也用了。而现在这段代码中取消第二个类的夹具,结果:

python测试(16)_第3张图片

很显然没有使用夹具,但是测试用例依旧会执行

而且测试函数和测试函数等可以同时使用

例如:

import pytest

@pytest.fixture(scope='class')
def go_try():
    print('我是前置测试类代码')
    yield
    print('我是后置测试类代码')

@pytest.fixture
def go_to_try():
    print('我是前置测试类代码')
    yield
    print('我是后置测试类代码')


@pytest.mark.usefixtures('go_to_try')
@pytest.mark.usefixtures('go_try')
class Test_001_try:
    def test_001_try(self):
        print('test new...')

    def test_002_try(self):
        print('test new1...')

    def test_003_try(self):
        print('test new2...')

在上述代码中定义了两个夹具,一个夹测试函数,一个夹测试类

class前两个都使用了,所以它得到的结果会是在最外面包一层测试类的夹具,其中的每一个函数又包一层测试函数的夹具:

python测试(16)_第4张图片

只要前置代码没有问题,一般都能直接走到后置代码

因为如果说不是前置代码出现了错误 ,那么不管用例成功与否都会被执行出来,不会说用例失败了就中断了,最后依旧走到后置阶段

前置阶段准备工作产生的数据应该如何被测试用例使用?

因为测试用例和fixture部分是分开的,所以fixture部分得到的数据是不能直接被测试用例使用的。

首先在fixture部分,直接在yield后面加上要返回的数据名

比如在下面这个代码中要将前置部分产生的随机数字传给测试用例:

import pytest
import uuid
@pytest.fixture(scope='class')
def go_try():
    print('我是前置测试类代码')
    token = uuid.uuid4()
    yield token
    print('我是后置测试类代码')

@pytest.mark.usefixtures('go_try')
class Test_001_try:
    def test_001_try(self):
        print('test new...')

    def test_002_try(self):
        print('test new1...')

    def test_003_try(self):
        print('test new2...')

其中的uuid是一个模块需要被导入,uuid.uuid4()是用来生成随机数的。上述代码中token用来接收产生的随机数,然后现在想要将这个值传递给测试用例,那么先在yield后面加上想要返回的变量名

但是这样测试用例那边还没有接收这个数据,那么测试用例怎么去接收呢?

还是以上面代码为例,加上需要的部分:

import pytest
import uuid
@pytest.fixture(scope='class')
def go_try():
    print('我是前置测试类代码')
    token = uuid.uuid4()
    print('token返回的值是:',token)
    yield token
    print('我是后置测试类代码')

@pytest.mark.usefixtures('go_try')
class Test_001_try:
    def test_001_try(self,go_try):
        print('token返回的值是:',go_try)
    def test_002_try(self):
        print('test new1...')

    def test_003_try(self):
        print('test new2...')

测试用例接收的方法就是 在需要该测试用例的函数 在进行定义的时候 在self后面 加上夹具中函数的名字 用该名字来接收 夹具函数的返回值

那么如果有多个返回值能否只接收其中一个值呢?

答案是不能的,用yield返回多个值后,如果后面某个函数进行了调用,那么这几个值已经都被接收了。(返回多个值的话 就是在yield后面 直接加变量名 后面再加逗号 再加另外的变量就行)

比如:

import pytest
import uuid
@pytest.fixture(scope='class')
def go_try():
    print('我是前置测试类代码')
    token = uuid.uuid4()
    print('token返回的值是:',token)
    yield token,'1,2,3'
    print('我是后置测试类代码')

@pytest.mark.usefixtures('go_try')
class Test_001_try:
    def test_001_try(self,go_try):
        print('token返回的值是:',go_try)
    def test_002_try(self):
        print('test new1...')

    def test_003_try(self):
        print('test new2...')

此处的test_001_try函数调用了夹具中定义的函数,所以它接收到了token"1,2,3"。所以说多个返回值如果被调用了都是一起的。

那么,多个返回值一起返回,返回值会是什么类型呢?

例如:

import pytest
import uuid
@pytest.fixture(scope='class')
def go_try():
    print('我是前置测试类代码')
    token = uuid.uuid4()
    yield token,'1,2,3'
    print('我是后置测试类代码')

@pytest.mark.usefixtures('go_try')
class Test_001_try:
    def test_001_try(self,go_try):
        print('go_try返回的值是:',go_try)
        print('go_try返回值的类型是:',type(go_try))
    def test_002_try(self):
        print('test new1...')

    def test_003_try(self):
        print('test new2...')

该段代码中倒数5,6行 通过运行结果就可以知道 夹具中函数go_try返回的是什么类型

运行结果:

python测试(16)_第5张图片

根据结果:显然 多个返回值一起 返回得到的 返回值的类型是元组

如果不想一起以元组的形式返回,想单独返回每一个数据,有一种方法:

用多个变量名去接收函数的多个返回值

import pytest
import uuid
@pytest.fixture(scope='class')
def go_try():
    print('我是前置测试类代码')
    token = uuid.uuid4()
    yield token,'1,2,3'
    print('我是后置测试类代码')

@pytest.mark.usefixtures('go_try')
class Test_001_try:
    def test_001_try(self,go_try):
        a,b = go_try
    def test_002_try(self):
        print('test new1...')

    def test_003_try(self):
        print('test new2...')

第12行代码中就是用a和b两个变量去接收返回值,a得到第一个数据,b得到第二个数据 (注意:只有元组有这种用法,其他数据类型没有)

fixture的共享机制

在前面的介绍中,fixture和用例是放在一个模块下的。如果说将fixture单独放在一个模块下,那么用例应该如何去使用这个夹具呢?——答案就是在用例的父级目录下新建一个名为conftest.py的文件,注意这里的文件名字是不可以改变的!!!将定义夹具fixture的代码放到里面。

存放用例的模块直接使用就行,不用去调用,因为它有个机制会自动在父级目录下寻找conftest.py文件。

值得注意的是该conftest.py模块的作用域只在它所在的文件夹下面,超出这个它所在的文件夹去使用它就会识别不到

例如:

python测试(16)_第6张图片

conftest.py文件在pythonProject2文件夹下,那么只有在这个文件夹里面的文件可以使用该conftest.py文件

例如在test_02.py文件里面的用例想要使用夹具:

python测试(16)_第7张图片

从图中易看出在test_02.py中可以直接去使用,不用去调用什么的

结果:

python测试(16)_第8张图片

当然不同的文件夹下可以新建多个conftest.py文件。如果说一个存放用例的模块想要使用夹具,那么它就会去寻找conftest.py文件,有多个conftest.py文件的话,它寻找的方向就是:先看该用例的模块下有没有夹具,没有的话就在同一文件夹下找,找不到就一级一级往上找,找到了就会停止。

fixture并不是一定要共享,不需要共享的夹具可以就写在当下用例的目录下。不同的文件下写conftest.py文件,虽然看上去有些乱,好像不知道到底要使用哪个conftest.py文件,但是实际上,哪些用例需要使用哪些夹具我们自己是可以控制的。一般写在根目录上的conftest.py文件是全局共享的,可能整个项目的用例都需要一样的前置准备工作和后置清理工作。

你可能感兴趣的:(python,开发语言,pycharm,自动化,功能测试)