51Testing软件测试论坛

 找回密码
 (注-册)加入51Testing

QQ登录

只需一步,快速开始

微信登录,快人一步

手机号码,快捷登录

查看: 4990|回复: 1
打印 上一主题 下一主题

[原创] pytest中fixture详解

[复制链接]
  • TA的每日心情
    擦汗
    昨天 09:02
  • 签到天数: 1046 天

    连续签到: 4 天

    [LV.10]测试总司令

    跳转到指定楼层
    1#
    发表于 2021-3-11 09:25:25 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
    前言
      在做自动化的过程中,编写用例时候需要用到用例的前置和用例的后置,其中pytest中有setup_class和teardown_class可以帮助我们完成这些,但是不够完善而且灵活性不够强。举个简单的例子,一个calss中有3条用例,其中2条需要登录,1条不需要登录,这个时候如果在用setup和teardown来做就有点不方便。这个时候就引入了新的知识点fixture。
      fixture简单介绍
      fixture属于pytest中的一个方法。fixture可以用作[url=]测试[/url]用例的前置和后置操作,其中fixture命令规范没有像setup和teardown固定格式。可以随意命名。控制fixture的前置和后置操作是通过yield关键字进行来区分的,代码在yield前面的属于前置操作,代码在yield后面的属于后置操作。并且fixture也没有强烈的要求必须要前后置同时存在,可以只存在前置也可以只存在后置。fixture如果有后置内容,无论遇到什么问题,都会进行执行后置的代码。
      源码:
    def fixture(  # noqa: F811
        fixture_function: Optional[_FixtureFunction] = None,
        *,
        scope: "Union[_Scope, Callable[[str, Config], _Scope]]" = "function",
        params: Optional[Iterable[object]] = None,
        autouse: bool = False,
        ids: Optional[
            Union[
                Iterable[Union[None, str, float, int, bool]],
                Callable[[Any], Optional[object]],
            ]
        ] = None,
        name: Optional[str] = None
    ) -> Union[FixtureFunctionMarker, _FixtureFunction]:
        fixture_marker = FixtureFunctionMarker(
            scope=scope, params=params, autouse=autouse, ids=ids, name=name,
        )
        # Direct decoration.
        if fixture_function:
            return fixture_marker(fixture_function)
        return fixture_marker


      通过上述源码可以看到,fixture中一共有5个参数分别是:scope,params,autouse,ids,name。具体每个参数代表什么先不解释,后面会介绍到。

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


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

    import pytest
    @pytest.fixture()
    def login():
        print('登录操作')
        yield
        print('退出登录')
    class Test_Login():
        def test_01(self, login):
            print('需要用到登录!')
        def test_02(self):
            print('不需要登录!')
        def test_03(self, login):
            print('这里需要用到登录!')
    if __name__ == '__main__':
        pytest.main(['-vs'])


      通过查看执行后的结果发现,login的fixture已经在test_01和test_03中进行使用到了。test_02没有用到登录。这里也没有给他传入,对应的结果也是没用登录。
      从单纯的图片上看可能不是很明显,在命令行参数上加上--setuo-show进行详细打印出fixture在具体那条用例上进行生效。

      用例异常后继续执行后置操作
      前面提到过用例出现异常后,fixture继续执行后置操作。这里安静也距离给大家说明。
      将上面的代码用例中加入断言内容,保证用例3断言失败,看看是否会执行后置操作(退出登录)。
    import pytest
    @pytest.fixture()
    def login():
        print('登录操作')
        yield
        print('退出登录!')
    class Test_Login():
        def test_01(self, login):
            print('需要用到登录!')
            assert 1==1
        def test_02(self):
            print('不需要登录!')
        def test_03(self, login):
            print('这里需要用到登录!')
            assert 1==2
    if __name__ == '__main__':
        pytest.main(['-vs']


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


      多个fixture同时使用
      fixture不仅仅能单个使用,还能一起使用。使用的执行顺序取决于你传入的顺序决定,意思就是,先传的先执行。
    import pytest
    @pytest.fixture()
    def login():
        print('登录操作')
        yield
        print('退出登录!')
    @pytest.fixture()
    def log():
        print('打开日志功能!')
        yield
        print('关闭日志功能!')

    class Test_Login():
        def test_01(self, login, log):
            print('需要用到登录!')
        def test_02(self):
            print('不需要登录!')
        def test_03(self, log, login):
            print('这里需要用到登录!')
    if __name__ == '__main__':
        pytest.main(['-vs'])


      通过下图执行结果可以看出,test_01先执行的前置操作是login的,test_03先执行的前置操作是log的。

      fixture相互调用
      你以为fixture的功能就这么多了?当然不是了,fixture还可以进行其他fixture的调用操作。
      调用方法:直接将被调用fixture的函数名放到调用的fixture当做参数传入。
    import pytest
    @pytest.fixture()
    def login():
        print('\n登录操作')
        yield
        print('\n退出登录!')

    @pytest.fixture()
    def log(login):
        print('\n打开日志功能!')
        yield
        print('\n关闭日志功能!')
    class Test_Login():
        def test_01(self, log):
            print('\n需要用到登录!')
        def test_02(self):
            print('\n不需要登录!')
        def test_03(self, log):
            print('\n这里需要用到登录!')
    if __name__ == '__main__':
        pytest.main(['-vs'])


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


      fixture参数详解
      上面介绍了如何使用fixture,以及fixture的之间的相互调用。前面也留下来一个问题就是关于fixture的5个参数都表示什么意思。5个参数分别是name,scope,params,autouse,ids,。安静一个个给大家解释。
      name
      name参数表示可以对fixture的名称进行重命名。
    import pytest
    @pytest.fixture(name='anjing')
    def login():
        print('\n登录操作')
        yield
        print('\n退出登录!')
    class Test_Login():
        def test_01(self, anjing):
            print('---用例01---')
        def test_02(self):
            print('---用例02---')
        def test_03(self, anjing):
            print('---用例03---')
    if __name__ == '__main__':
        pytest.main(['-vs'])


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

      注意:通过name重命名后,继续使用以前的名字调用会报错。
      scope
      fixture中的参数scope是用于控制fixture的作用范围。
      源码:
      _Scope = Literal["session", "package", "module", "class", "function"]

      截图了源码中的主要一部分,这个标识scope中控制的还有其他的几种参数,“session”,“package”,“module”,“class”,“function”。
      其中scope默认参数为function,表示应用于单个测试函数中。
      session:主要应用于会话级别的fixture。
      module:主要应用于模块级别的fixture。
      class:主要应用于class中,表示每个前置和后置都会执行一次。
      package:主要应用于每个包下的fixture。
    import pytest
    @pytest.fixture(scope='session')
    def fix_session():
        print('\n这是属于session')
        yield
        print('\nsession')
    @pytest.fixture(scope='class')
    def fix_class():
        print('\n这是属于class')
        yield
        print('\nsession')
    @pytest.fixture(scope='module')
    def fix_module():
        print('\n这是属于module')
        yield
        print('\nmodule')
    @pytest.fixture(scope='function')
    def fix_function():
        print('\n这是属于function')
        yield
        print('\nfunction')
    class Test_01:
        def test_01(self, fix_function, fix_class,fix_module,fix_session):
            print('----用例01---')
    if __name__ == '__main__':
        pytest.main(['-vs'])


      通过执行会发现他们的执行顺序在不同的fixture作用范围内的执行顺序是不同的。

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

      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'])


      通过执行结果可以查看到我们当前的用例模块全部都调用了login。

      params
      params表示fixture的参数化功能。参数化这里就不用多说了吧。
      这里会有一个request参数,主要用来接收fixture的返回结果。并通过request.param返回结果内容。
    import pytest
    data = ['anjing', 'test', 'admin']
    @pytest.fixture(params=data)
    def login(request):
        print('登录功能')
        yield request.param
        print('退出登录')

    class Test_01:
        def test_01(self, login):
            print('---用例01---')
            print('登录的用户名:%s' % login)
        def test_02(self):
            print('---用例02---')

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


      通过执行结果可以看到,我们的test_01一共执行了3次,每次都是不同的参数,参数也是通过login进行接收的。


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

    @pytest.fixture(params=data, ids=['user=anjing','user=test','user=admin'])
    def login(request):
        print('登录功能')
        yield request.param
        print('退出登录')

    class Test_01:
        def test_01(self, login):
            print('---用例01---')
            print('登录的用户名:%s' % login)
        def test_02(self):
            print('---用例02---')

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


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


    分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
    收藏收藏
    回复

    使用道具 举报

    本版积分规则

    关闭

    站长推荐上一条 /1 下一条

    小黑屋|手机版|Archiver|51Testing软件测试网 ( 沪ICP备05003035号 关于我们

    GMT+8, 2024-11-15 00:33 , Processed in 0.065682 second(s), 22 queries .

    Powered by Discuz! X3.2

    © 2001-2024 Comsenz Inc.

    快速回复 返回顶部 返回列表