使用 Python 语言 从 0 到 1 搭建完整 Web UI自动化测试学习系列 19--测试框架Pytest基础 3--前后置操作应用
测试学习记录,仅供参考!
Pytest 框架
九、前后置处理
在测试框架中,前后置是指在执行测试用例前和执行测试用例后一些额外的操作,这些操作可以用于设置测试环境、准备测试数据等,以确保测试的可靠性和一致性。在 pytest 框架中提供了三种前后置操作的处理方式。
1、setup、teardown、setup_class、teardown_class 等等
setup 和 teardown 名称是固定的,不能随便更改;
使用 setup 方法能够进行测试用例执行前的初始化、参数配置等等;
使用 teardown 方法可以进行测试用例执行后的脏数据清理、还原、关闭、退出等操作;
自行了解学习(此种方式在 pytest 框架中不常用)
类方法细化级别 setup()、teardown(),类里面的,运行在调用方法的前后;
类级别:setup_class()、teardown_class(),只在类中前后运行一次;
类方法级别:setup_method()、teardown_method(),在类中,开始于方法始末;
模块级别:setup_module()、teardown_module(),全局的,开始于模块始末;
函数级别:setup_function()、teardown_function(),不在类中,只对函数方法测试用例生效;
setup、teardown 的用法:测试类中的测试用例执行前各执行一次前后置操作;
setup_class、teardown_class 的用法:测试类中的测试用例执行前只执行一次前后置操作;
setup_method、teardown_method 的用法:类中每个测试方法前执行;
setup_module、teardown_module 的用法:整个模块开始前执行一次;
setup_function、teardown_function 的用法:每个方法函数测试用例开始和结束执行一次;
2、使用 pytest 框架里面的 @pytest.fixture 装饰器
装饰器 @pytest.fixture 又称作脚手架、夹具等名称,用于声明函数是一个 fixture,它的名称默认为函数名,亦可以通过参数指定名称别名,它用 pytest.fixture 标识,定义在函数前面,若测试用例的参数列表中包含 fixture 的名称,则 pytest 会根据名称自动检测到此 fixture,在函数方法测试用例执行前运行此 fixture;
1) 在一个函数中使用 @pytest.fixture 实现前后置操作,并且 @pytest.fixture 不带参数
例如 自定义函数(方法)def init_browser(): 加上 @pytest.fixture 后就不再是一个普通函数,而是一个前置应用,当 @pytest.fixture() 里面没有参数时,需要手动去调用前置,哪个测试用例需要用到前置操作就在哪个测试用例加上前置函数名称即可;
import pytest@pytest.fixture
def init_browser():print('前置操作,初始化浏览器对象')class TestFixture:def test_case_01(self, init_browser):print('fixture第一个测试用例')def test_case_02(self):print('fixture第二个测试 用例')
在一个函数中实现前置和后置操作,再增加后置应用;
需要在函数 def setup(): 里面增加 request (参数名称固定写法,作用于上下文的操作),然后通过 request 调用 addfinalizer() 方法,里面传后置应用 teardown 函数名;
import pytest@pytest.fixture
def setup(request):print('前置操作,初始化浏览器对象')def teardown():print('后置操作,关闭浏览器对象,清理数据')# 将teardown函数注册为最终器,以确保在测试用例运行结束后执行后置操作request.addfinalizer(teardown)# 注册为最终器之后需要把结果返回出去return teardownclass TestFixture:# 若前置函数@pytest.fixture不带参数,则需要手动使用前置def test_case_01(self, setup):print('fixture第一个测试用例')def test_case_02(self):print('fixture第二个测试 用例')
这种方式不常见,了解即可;
2) 使用 yield 关键字去实现一个函数里面的前后置操作
<在Python中,yield
关键字主要用于生成器(generator)中,它允许函数在执行过程中暂停,并返回一个值,之后再继续执行,而不是一次性返回所有的值。这使得函数能够逐个生成值,而不是一次性生成一个完整的列表或数组。这对于处理大量数据或需要节省内存的场景特别有用。
在pytest
测试框架中,通常不直接使用yield
来编写测试用例(测试用例通常是使用def
定义的函数),但可以利用yield
在编写测试数据生成器或在测试中实现一些特殊的行为。
yield 是一个关键字,它不是单独存在的,要写在 fixture 标记的函数方法中;
使用 yield 关键字,上(前)面写前置操作,下(后)面写后置操作;后续编写框架时,在一个函数方法中实现前后置操作大部分均是使用 yield 关键字;这种写法比上面一种写法更要简洁;
import pytest@pytest.fixture
def setup():print('前置操作,初始化浏览器对象')yieldprint('后置操作,关闭浏览器对象,清理数据')class TestFixture:# 若前置函数@pytest.fixture不带参数,则需要手动使用前置def test_case_01(self, setup):print('fixture第一个测试用例')def test_case_02(self):print('fixture第二个测试 用例')
3)带参数的 @pytest.fixture() 前后置
里面可以跟五个参数,前面两个使用比较多,需要掌握,后面三个用到的不是很多,特别是后面两个,了解即可;
@pytest.fixture(scope='', autouse='', params='', ids='', name='')
(1)scope
scope:控制 fixture 的作用范围,可选值有“function”、“class”、“module”、“session”,scope='' 只能选择这四个其中之一;scope 参数可以单独使用;
function:默认,每个测试函数执行前后运行一次;
class:每个测试类执行前后运行一次;
module:每个模块执行前后运行一次(即每个 xx.py 文件)
session:会话级别,作用比较广,整个 pytest 会话(多个模块)执行前后运行一次;
(2)autouse
autouse:用于指定是否自动应用 fixture 而无需在测试函数中显示调用,默认 False ;可单独使用;
import pytest@pytest.fixture(scope='class', autouse=True)
def setup():print('前置操作,初始化浏览器对象')yieldprint('后置操作,关闭浏览器对象,清理数据')class TestFixture:# 若前置函数@pytest.fixture的参数autouse=True,则无需在测试函数中手动显示调用def test_case_01(self):print('fixture第一个测试用例')def test_case_02(self):print('fixture第二个测试 用例')
(3)params
params:用于参数化的一个选项,它允许为 fixture 定义多个参数值,以便在测试函数中使用不同的参数组合运行测试;一般情况下 params 参数用的不是很多;可单独使用;
定义一个参数化数据 params 为一个列表,里面有 3 个数据;
使用 request.param(固定写法) 去接收参数化里面的参数, def setup() 函数方法里面需要用到 request 去接收 params 参数化里面的 3 个数据参数,再把值给返回出去赋给 value,最后再 return 一下返回 value;
只给 setup 前置操作传了 3 个数据;
def test_case_01(self, setup): 这条测试用例使用了 setup 前置操作, setup 前置里面有 3 个自定义数据,使用request.param 去接收到参数化(params)的参数(3 个自定义数据),然后使用 return 把它返回出去;相当于 这个前置操作就是一组数据了,把数据传给测试用例def test_case_01(self, setup)之后再去使用 assert 断言列表中的 3 个数据字符长度是否大于 0 ;
可以使用 @pytest.fixture() 做前后置的一个参数化,传给需要使用的测试函数;
import pytest@pytest.fixture(params=['App', 'Ios', 'Android'])
def setup(request):value = request.paramreturn valueclass TestFixture:def test_case_01(self, setup):assert len(setup) > 0
(4)ids
ids:为参数化的 fixture 提供自定义的标识,用于在测试报告中更清晰地显示参数;没有实际作用,不常用,一般与 params 参数结合使用,给参数取个别名,了解即可;
import pytest@pytest.fixture(params=['App', 'Ios', 'Android'], ids=['test01', 'test02', 'test03'])
def setup(request):value = request.paramreturn valueclass TestFixture:def test_case_01(self, setup):assert len(setup) > 0
(5)name
name:自定义 fixture 的名称,没有特别的实际意义;一般不怎么使用,了解即可;
当使用 name='test' 参数给前置操作取了名称成功之后,就表示前置操作 setup 名称就变成自定义的 test 名称了,不在是以 setup 名称为主了,后续在测试用例中需要调用自定义的 test 名称;
import pytest@pytest.fixture(params=['App', 'Ios'], ids=['test01', 'test02'], name='test')
def setup(request):value = request.paramreturn valueclass TestFixture:def test_case_01(self, test):assert len(test) > 0
3、conftest.py 和 @pytest.fixture 装饰器结合使用实现全局的前后置应用
使用 conftest.py 内置文件,它是 pytest 里面内置的一个文件名(名称固定写法),在启动执行时,会在项目中查找是否存在 conftest.py 文件,若有 conftest.py 文件则会读取里面的代码操作;
@pytest.fixture 与 conftest.py 文件结合使用,可以实现在多个测试模块(.py 文件)中共享前后置操作,这种结合的方式使得可以在整个测试项目中定义和维护通用的前后置逻辑,使测试代码更加模块化和可维护。
module(模块级别)和 session(会话级别)需要跟 conftest.py 文件结合使用才能看到效果;
规则:
(1)conftest.py 是一个单独存放的夹具配置文件,名称是固定的不能修改;
(2)可以在项目中的不同目录下创建多个 conftest.py 文件,每个 conftest.py 文件都会对其所在目录及其子目录下的测试模块生效;
(3)在不同模块的测试中需要用到 conftest.py 的前后置功能时,不需要做任何的 import 导入操作;
(4)作用:可以在不同的 py 文件中使用同一个 fixture 函数;
在项目根目录下新建一个名称为 conftest.py 的 Python 文件,里面写前后置操作;可以酌情考虑是否添加日志;
import pytest
from util_tools.logs_util.recordlog import logs@pytest.fixture(scope='module', autouse=True)
def setup():logs.info('前置操作,初始化浏览器对象----测试用例开始执行----')yieldlogs.info('后置操作,关闭浏览器对象----测试用例执行完毕----')
执行主函数 run.py 文件查看测试结果;
未完待续。。。