Pytest中fixture的作用范围(六)

  • 2019 年 10 月 7 日
  • 筆記

前面介绍了fixture的参数化,以及conftest.py的系列知识,本文章主要总结fixture的参数scope,通过它可以指定fixture的作用范围。scope的参数主要应用于控制fixture执行配置和销毁逻辑的频率。在scope的参数中主要有四个值可以选择,分别是function(函数级别),class(类级别).module(模块级别),session(会话级别),它的默认值是函数级别。下面依据各个案例来说明该参数的实际应用。

先来看函数级别,也就是说函数级别中,每个测试函数只需要执行一次,配置代码在测试用例运行前执行,销毁代码是在测试用例运行之后执行。见案例代码:

#!/usr/bin/python3  #coding:utf-8  import  pytest    @pytest.fixture(scope='function')  def api():      print('开始执行')      yield      print('结束执行')      def test_login_001(api):      assert  1==1

该fixture仅仅是函数级别的应用,不会应用于其他的方面,见执行后的结果信息:

platform darwin -- Python 3.7.4, pytest-4.0.2, py-1.8.0, pluggy-0.12.0  rootdir: /Applications/code/stack/study/xunit/scope, inifile:  plugins: html-1.22.0, allure-adaptor-1.7.10, metadata-1.8.0  collected 1 item    test_001.py          SETUP    F api          test_001.py::test_login_001 (fixtures used: api).          TEARDOWN F api

下来看类级别的,类级别的主要指的是每个测试类需要运行一次,无论测试类里面有多少个测试方法,都会被执行到并且共享fixture,见案例代码:

#!/usr/bin/python3  #coding:utf-8  import  pytest    @pytest.fixture(scope='class')  def api():      print('开始执行')      yield      print('结束执行')        class TestLogin(object):      def test_login_001(self,api):          assert  1==1      def test_login_002(self):          assert  1==1

见执行后的结果信息:

platform darwin -- Python 3.7.4, pytest-4.0.2, py-1.8.0, pluggy-0.12.0  rootdir: /Applications/code/stack/study/xunit/scope, inifile:  plugins: html-1.22.0, allure-adaptor-1.7.10, metadata-1.8.0  collected 2 items    test_001.py        SETUP    C api          test_001.py::TestLogin::test_login_001 (fixtures used: api).          test_001.py::TestLogin::test_login_002 (fixtures used: api).        TEARDOWN C api

来来看模块级别的,在模块级别的fixture每个模块只需要执行一次,无论模块里面有多少个测试函数,类方法,都可以共享这个fixture,见案例代码:

import  pytest    @pytest.fixture(scope='module')  def api():      print('开始执行')      yield      print('结束执行')    def test_login_001(api):      assert  1==1  class TestApi(object):      def test_api_001(self,api):          assert  1==1

见执行后的输出信息:

platform darwin -- Python 3.7.4, pytest-4.0.2, py-1.8.0, pluggy-0.12.0  rootdir: /Applications/code/stack/study/xunit/scope, inifile:  plugins: html-1.22.0, allure-adaptor-1.7.10, metadata-1.8.0  collected 2 items    test_001.py      SETUP    M api          test_001.py::test_login_001 (fixtures used: api).          test_001.py::TestApi::test_api_001 (fixtures used: api).      TEARDOWN M api

是否存在这样的一个疑问,函数级别的是否可以应用在类级别,类级别的是否可以应用于函数级别了,见测试代码:

import  pytest    @pytest.fixture(scope='function')  def api():      print('开始执行')      yield      print('结束执行')    def test_login_001(api):      assert  1==1  class TestApi(object):      def test_api_001(self,api):          assert  1==1

见输出的信息:

platform darwin -- Python 3.7.4, pytest-4.0.2, py-1.8.0, pluggy-0.12.0  rootdir: /Applications/code/stack/study/xunit/scope, inifile:  plugins: html-1.22.0, allure-adaptor-1.7.10, metadata-1.8.0  collected 2 items    test_001.py          SETUP    F api          test_001.py::test_login_001 (fixtures used: api).          TEARDOWN F api          SETUP    F api          test_001.py::TestApi::test_api_001 (fixtures used: api).          TEARDOWN F api

最后一个是会话级别的,会话级别的fixture每次会话只需要运行一次,一次pytest会话中的所有测试函数,方法都可以共享该fixture,见案例代码:

#!/usr/bin/python3  #coding:utf-8  import  pytest    @pytest.fixture(autouse=True,scope='session')  def wuya():      print('start')      yield      print('end')

见测试的代码:

#!/usr/bin/python3  #coding:utf-8  import  pytest    def test_login_001():      assert  1==1  class TestApi(object):      def test_api_001(self):          assert  1==1

见执行后输出的结果信息:

platform darwin -- Python 3.7.4, pytest-4.0.2, py-1.8.0, pluggy-0.12.0  rootdir: /Applications/code/stack/study/xunit/scope, inifile:  plugins: html-1.22.0, allure-adaptor-1.7.10, metadata-1.8.0  collected 2 items    test_001.py  SETUP    S wuya          test_001.py::test_login_001 (fixtures used: wuya).          test_001.py::TestApi::test_api_001 (fixtures used: wuya).  TEARDOWN S wuya

在pytest中也可以使用userfixture指定多个fixture,这样来标记测试函数或者测试的类,使用usefixture,需要在一个参数中指定一个或者多个fixture字符串,这样的一个场景在特定的场景下还是可以的,见案例的测试代码:

#!/usr/bin/python3  #coding:utf-8  import  pytest    @pytest.fixture()  def api():      return 1  @pytest.fixture()  def init():      print('start')      yield      print('end')    @pytest.mark.usefixtures('api','init')  def test_login_001(api):      assert  api==1

见执行后输出的信息:

platform darwin -- Python 3.7.4, pytest-4.0.2, py-1.8.0, pluggy-0.12.0  rootdir: /Applications/code/stack/study/xunit/scope, inifile:  plugins: html-1.22.0, allure-adaptor-1.7.10, metadata-1.8.0  collected 1 item    test_001.py          SETUP    F api          SETUP    F init          test_001.py::test_login_001 (fixtures used: api, init).          TEARDOWN F init          TEARDOWN F api

在如上的结果信息中,就可以看到,测试函数共享了两个fixture。

在前面使用fixture的时候说到了autouse的选项,也应该看到,如果不使用该选项,每次共享fixture都需要指定,但是使用了它后就不需要指定了,那么标准的说法应该是:依据选项autouse=True,使作用域内的测试函数都执行该fixture,这与那些需要多次执行,但不依赖任何的状态或者外部数据的代码配合的比较好。针对如上的代码修改,见修改后的源码:

#!/usr/bin/python3  #coding:utf-8  import  pytest    @pytest.fixture(autouse=True)  def api():      return 1  @pytest.fixture(autouse=True)  def init():      print('start')      yield      print('end')      def test_login_001(api):      assert  api==1

见执行后输出的结果信息:

platform darwin -- Python 3.7.4, pytest-4.0.2, py-1.8.0, pluggy-0.12.0  rootdir: /Applications/code/stack/study/xunit/scope, inifile:  plugins: html-1.22.0, allure-adaptor-1.7.10, metadata-1.8.0  collected 1 item    test_001.py          SETUP    F api          SETUP    F init          test_001.py::test_login_001 (fixtures used: api, init).          TEARDOWN F init          TEARDOWN F api