Pytest Fixture详解

 前言

  在做自动化的过程中,编写用例时候需要用到用例的前置和用例的后置,其中pytest中有setup_class和teardown_class可以帮助我们完成这些,但是不够完善而且灵活性不够强。举个简单的例子,一个calss中有3条用例,其中2条需要登录,1条不需要登录,这个时候如果在用setup和teardown来做就有点不方便。这个时候就引入了新的知识点fixture。

Fixture简单介绍

  fixture属于pytest中的一个方法。fixture可以用作测试用例的前置和后置操作,其中fixture命令规范没有像setup和teardown固定格式。可以随意命名。控制fixture的前置和后置操作是通过yield关键字进行来区分的代码在yield前面的属于前置操作,代码在yield后面的属于后置操作。并且fixture也没有强烈的要求必须要前后置同时存在,可以只存在前置也可以只存在后置。fixture如果有后置内容,无论遇到什么问题,都会进行执行后置的代码。

return和yeild的区别: 都是表示返回值的意思,但是return的后面不能有代码,yeild很后面可以有代码

yield语句之前的就会在测试用例之前使用,yield之后的语句就会在测试用例执行完成之后再执行。

常见的应用场景:

  1. @pytest.fixture可以用在selenium中测试用例执行前后打开、关闭浏览器的操作; yield返回driver对象去操作浏览器;
  2. @pytest.fixture可以用在接口自动化测试中操作登录,yield返回token;

fixture中一共有5个参数分别是:scope,params,autouse,ids,name

fixture使用方法

  前面已经介绍了fixture是干什么的,但是具体的用法没有说,先介绍下具体用法,这里通过将登录操作写在一个函数中。然后通过装饰器的方法进行使其变成fixture。那条用例需要用到对应的前置和后置操作的时,直接将fixture的名称通过传参的形式放到用例中。

一个class中存在3条用例,其中2条需要登录,1条不需要登录。运营fixture进行完成前后置操作。

import pytest
@pytest.fixture()
def login():
    print("log In")
    yield "Token:xxxxxxxxxxxxxxxxx" #yield之前的内容是setup的相关内容,之后的内容是teardown的操作
    print("Log out")

class TestFixture:

    def test_case001(self,login):
        assert 1==1
        
      def test_case002(self):
        assert 1==1

    def test_case003(self,login):
        assert 2==1

通过查看执行后的结果发现,login的fixture已经在test_001和test_003中进行使用到了。test_002没有用到登录。这里也没有给他传入,对应的结果也是没用登录。

Pytest Fixture详解_第1张图片

用例异常后继续执行后置操作

  前面提到过用例出现异常后,fixture继续执行后置操作。这里安静也距离给大家说明。

  将上面的代码用例中加入断言内容,保证用例3断言失败,看看是否会执行后置操作(退出登录)。

  通过执行发现,我们的test_003断言失败后,继续执行了退出登录操作。也就是后置内容。

多个fixture同时使用

  fixture不仅仅能单个使用,还能一起使用。使用的执行顺序取决于你传入的顺序决定,意思就是,先传的先执行。

import pytest
@pytest.fixture()
def login():
    print("login begin")
    yield "Token:xxxxxxxxxxxxxxxxx"
    print("login end")

@pytest.fixture()
def logFunc():
    print("logFunc  begining")
    yield
    print("logFunc  finished")

class TestFixture:
    #先login 在执行log
    def test_case001(self,login,logFunc):
        assert 1==1

    def test_case002(self):
        assert 1==1
     #先log 在执行login
    def test_case003(self,logFunc,login):
        assert 2==2

if __name__ == '__main__':
    pytest.main()

通过下图执行结果可以看出,test_001先执行的前置操作是login的,test_003先执行的前置操作是logFunc的。

Pytest Fixture详解_第2张图片

fixture相互调用

  你以为fixture的功能就这么多了?当然不是了,fixture还可以进行其他fixture的调用操作

  调用方法:直接将被调用fixture的函数名放到调用的fixture当做参数传入。

import pytest
@pytest.fixture()
def login():
    print("登录操作")
    yield "Token:xxxxxxxxxxxxxxxxx"
    print("退出登录")

@pytest.fixture()
def logFunc(login):# log调用login功能
    """
    打开日志前需要先登录
    :param login:
    :return:
    """
    print("Log begining")
    yield
    print("log finished")

class TestFixture:

    def test_case001(self,login,logFunc):
        assert 1==1

    def test_case002(self):
        assert 1==1

    def test_case003(self,logFunc,login):
        assert 1==1

if __name__ == '__main__':
    pytest.main()

这里只需要传入一个参数即刻。通过执行发现,已经成功的调用了2个fixture的内容。

fixture参数详解

上面介绍了如何使用fixture,以及fixture的之间的相互调用。前面也留下来一个问题就是关于fixture的5个参数都表示什么意思。5个参数分别是name,scope,params,autouse,ids,。安静一个个给大家解释。

name

  name参数表示可以对fixture的名称进行重命名。

import pytest
@pytest.fixture(name="Test123")
def login():
    print("登录操作")
    yield "Token:xxxxxxxxxxxxxxxxx"
    print("退出登录")

@pytest.fixture()
def logFunc():
    """
    打开日志前需要先登录
    :param login:
    :return:
    """
    print("Log begining")
    yield
    print("log finished")

class TestFixture:

    def test_case001(self,Test123,logFunc):
        assert 1==1

    def test_case002(self):
        assert 1==1

    def test_case003(self,logFunc,Test123):
        assert 1==1

if __name__ == '__main__':
    pytest.main()

执行后发现,通过参数name更改过的名字可以直接进行调用。

注意:通过name重命名后,继续使用以前的名字调用会报错。

scope

  fixture中的参数scope是用于控制fixture的作用范围。

  scope中控制的还有其他的几种参数,“session”,“package”,“module”,“class”,“function”。

  其中scope默认参数为function,表示应用于单个测试函数中。

  session:主要应用于会话级别的fixture。

  module:主要应用于模块级别的fixture(单个.py文件)。

  class:主要应用于class中,表示每个前置和后置都会执行一次。

  package:主要应用于每个包下的fixture。

执行顺序:session>>module>>class>>function

import pytest

@pytest.fixture(scope='session')
def fix_session():
    print("这是session")
    yield
    print("session 结束")

@pytest.fixture(scope='class')
def fix_class():
    print("这是class")
    yield
    print("class 结束")

@pytest.fixture(scope='module')
def fix_module():
    print("这是module")
    yield
    print("module 结束")

@pytest.fixture(scope='function')
def fix_function():
    print("这是function")
    yield
    print("function 结束")
class TestFixture:

    def test_case001(self,fix_function,fix_class,fix_module,fix_session):
        assert 1==1

if __name__ == '__main__':
    pytest.main()

Pytest Fixture详解_第3张图片

autouse

  autouse表示在fixture中用于控制fixture作用范围内的是否全部执行。默认为False,当设置为True的时候表示该fixture在当前作用范围内,全部执行。

import pytest

@pytest.fixture(autouse=True)
def login():
    print('\n登录操作')
    yield
    print('\n退出登录!')


class Test_Login():
    def test_01(self):
        print('---用例01---')

    def test_02(self):
        print('---用例02---')

    def test_03(self):
        print('---用例03---')


if __name__ == '__main__':
    pytest.main(['-vs'])

Pytest Fixture详解_第4张图片

params

  params表示fixture的参数化功能。参数化这里就不用多说了吧。

  这里会有一个request参数,主要用来接收fixture的返回结果。并通过request.param返回结果内容。

import pytest

data = ['user01','user02','user03']

@pytest.fixture(params=data)
def login(request):
    print('\n登录操作')
    yield request.param
    print('\n退出登录!')


class Test_Login():
    def test_01(self,login):
        print('---用例01---')
        print(f'登录的用户名:{login}')

    def test_02(self):
        print('---用例02---')

    def test_03(self):
        print('---用例03---')


if __name__ == '__main__':
    pytest.main(['-vs'])

这里只需要传入一个参数即可。通过执行发现,已经成功的调用了2个fixture的内容。

 ids

  ids表示在fixture对参数化的内容进行加上标识,比如让别人知道这个传入的参数是什么意思。用于什么样的测试用例。默认是传参数内容:

import pytest

data = ['user01','user02','user03']

@pytest.fixture(params=data,ids=['user=user01','user=user02','user=user03'])
def login(request):
    print('\n登录操作')
    yield request.param
    print('\n退出登录!')

class Test_Login():
    def test_01(self,login):
        print('---用例01---')
        print(f'登录的用户名:{login}')

    def test_02(self):
        print('---用例02---')

    def test_03(self):
        print('---用例03---')


if __name__ == '__main__':
    pytest.main(['-vs'])

 执行结果可以看到在每条用例的后面都会有对应的参数详解。

Pytest Fixture详解_第5张图片

你可能感兴趣的:(Pytest,pytest)