pytest扫盲4--fixture 作用域
1、fixture 作用
1)测试用例执行的环境准备工作和清理,在 unittest 中指 setUp(),tearDown()
2)提供一种可靠和可重复性的手段去运行哪些基本的测试内容,比如登录和退出,使用fixture只用做一次。
2、固定目录 conftest.py
1)固定目录,不可更改,每组用例目录可放一个,也可以添加多个fixtures
2)conftest.py 放在整个工程目录下,则作用于整个工程
3、 fixture 参数,源码如下(大致的意思标注在了解释文档后面):
def fixture( callable_or_scope=None, *args, scope="function", params=None, autouse=False, ids=None, name=None ): """Decorator to mark a fixture factory function. This decorator can be used,with or without parameters, to define a fixture function. # fixture的调用,可以带参数或者不带参数 The name of the fixture function can later be referenced to cause its invocation ahead of running tests: test modules or classes can use the ``pytest.mark.usefixtures(fixturename)`` marker. # 运行测试前先执行fixture,在modules和calsses中使用 pytest.mark.usefixtures(fixturename) 引用 Test functions can directly use fixture names as input arguments in which case the fixture instance returned from the fixture function will be injected. # fixture 可以直接作为输入参数传入函数中 Fixtures can provide their values to test functions using ``return`` or ``yield`` statements. When using ``yield`` the code block after the ``yield`` statement is executed as teardown code regardless of the test outcome, and must yield exactly once. # fixture 可以使用 return 和 yield 返回值,使用 yield 时,后面的代码块将作为 teardown 代码执行 :arg scope: the scope for which this fixture is shared, one of ``"function"`` (default), ``"class"``, ``"module"``, ``"package"`` or ``"session"`` (``"package"`` is considered **experimental** at this time). # 作用域:作用域可以被共享,共享可以选择在哪些级别共享,默认在 function 内共享 This parameter may also be a callable which receives ``(fixture_name, config)`` as parameters, and must return a ``str`` with one of the values mentioned above. See :ref:`dynamic scope` in the docs for more information. :arg params: an optional list of parameters which will cause multiple invocations of the fixture function and all of the tests using it. The current parameter is available in ``request.param``. # 可选的参数列表,fixture 会遍历 params=[a,b,c] 的内容,可以利用这个参数做数据驱动噢~ :arg autouse: if True, the fixture func is activated for all tests that can see it. If False (the default) then an explicit reference is needed to activate the fixture. # 自动使用:如果为True则自动使用,为False则需要调用来fixture :arg ids: list of string ids each corresponding to the params so that they are part of the test id. If no ids are provided they will be generated automatically from the params. # 字符串id列表,没搞太明白这个参数 :arg name: the name of the fixture. This defaults to the name of the decorated function. If a fixture is used in the same module in which it is defined, the function name of the fixture will be shadowed by the function arg that requests the fixture; one way to resolve this is to name the decorated function ``fixture_<fixturename>`` and then use ``@pytest.fixture(name='<fixturename>')``. # 修改 fixture 默认命名 """
4、fixture 的4种作用域
1:@pytest.fixture(),默认函数级别 scope='function'
# File : test_demo_3.py # IDE : PyCharm import pytest @pytest.fixture() # 默认作用级别 function def getPhoneNum(): print('\n获取电话') return '1008611' @pytest.fixture() def getEmail(): print('\n获取邮箱') return 'admin@163.com' class TestCases: def test_1(self, getPhoneNum): '''fixture(@scope='function')''' print('电话号码为{0}'.format(getPhoneNum)) assert getPhoneNum == '1008611' def test_2(self, getEmail): '''fixture(@scope='function')''' print('电话号码为{0}'.format(getEmail)) assert getEmail == 'admin@163.com' if __name__ == '__main__': pytest.main(["-s", "test_demo_3.py"])
============================= test session starts ============================= platform win32 -- Python 3.8.2, pytest-5.4.1, py-1.8.1, pluggy-0.13.1 rootdir: E:\personal\GitWorkSpace\pytest_basic plugins: html-2.1.1, metadata-1.8.0, rerunfailures-9.0 collected 2 items test_demo_3.py 获取电话 电话号码为1008611 . 获取邮箱 电话号码为admin@163.com . ============================== 2 passed in 0.03s ==============================
2:@pytest.fixture(scope='class'),类级别,在类中所有用例开始前只调用一次
# File : test_demo_4.py # IDE : PyCharm import pytest @pytest.fixture(scope='class') def login(): print('登录系统') return '登录成功' @pytest.mark.usefixtures('login') class TestCases(): def getPhoneNum(self): return '1008611' def getEmail(self): return 'admin@163.com' def test_1(self, login): '''fixture(@scope='class')''' phoneNum = self.getPhoneNum() print('执行test_1,电话号码为{0}'.format(phoneNum)) assert phoneNum == '1008611' def test_2(self): '''fixture(@scope='class')''' email = self.getEmail() print('\n执行test_1,邮箱为{0}'.format(email)) assert email == 'admin@163.com' if __name__ == '__main__': pytest.main(['-s', '-q', 'test_demo_4.py'])
E:/personal/GitWorkSpace/pytest_basic/main.py 登录系统 执行test_1,电话号码为1008611 . 执行test_1,邮箱为admin@163.com . 2 passed in 0.04s
3:@pytest.fixture(scope='module'),模块级别,在当前.py文件里面所有用例开始前只调用一次
# File : test_demo_5.py # IDE : PyCharm import pytest @pytest.fixture(scope='module') def login(): print('module级别,整个文件只登录一次') return '登录成功' def getPhoneNum(): return '1008611' def test_1(login): phoneNum = getPhoneNum() print('执行test_1函数,电话号码为{0}'.format(phoneNum)) assert phoneNum == '1008611' class TestCases(): def getEmail(self): return 'admin@163.com' def test_2(self, login): email = self.getEmail() print('\n执行TestCases()中方法test_2,邮箱为{0}'.format(email)) assert email == 'admin@163.com' if __name__ == '__main__': pytest.main(['-s', '-q', 'test_demo_5.py'])
E:/personal/GitWorkSpace/pytest_basic/main.py module级别,整个文件只登录一次 执行test_1函数,电话号码为1008611 . 执行TestCases()中方法test_2,邮箱为admin@163.com . 2 passed in 0.07s
4:@pytest.fixture(scope='session'),会话级别,通过 conftest.py 文件实现跨.py文件调用,所有文件用例执行前调用一次。
# File : conftest.py # IDE : PyCharm import pytest @pytest.fixture(scope='session') def login(): print('session级别登录,多个.py文件只登录一次')
# File : main.py # IDE : PyCharm import pytest
# 执行之前的代码块,加上 login,多个文件执行用逗号隔开 pytest.main(['-s', '-q', 'test_demo_1.py', 'test_demo_2.py'])
E:/personal/GitWorkSpace/pytest_basic/main.py session级别登录,多个.py文件只登录一次 F.F**********用例开始,只运行一次!********** **********用例开始!********** *****test_1***** .**********用例结束!********** **********用例开始!********** *****test_2***** F**********用例结束!********** **********用例开始!********** *****test_3***** F**********用例结束!********** **********用例结束,只运行一次!********** ================================== FAILURES ===================================
5)需求:上面所有的调用都只有前置操作,下篇利用 conftest.py 文件,使用 yield 实现后置操作
喜时之言,多失信;怒时之言,多失体