1 Star 1 Fork 1

兰夜/api_auto_frame_public

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
conftest.py 11.56 KB
一键复制 编辑 原始数据 按行查看 历史
行歌 提交于 2023-10-07 16:29 +08:00 . Initial commit
"""
# @File : conftest.py
# @remark : conftest.py配置脚本名称固定,pytest会自动识别该文件,对当前目录下和子目录生效
# @Author : 潘裕荣
"""
import pytest
from utils.allure_tools.allure_data import allure_step, allure_step_text, allure_title
from utils.data_handler.cache_control import SystemCacheHandler
from utils.case_handler.case_data_control import CaseDataControl
from utils.data_handler.sub_control import Sub
from utils.data_handler.data_models import TestCaseModel
from business.login.login import Login
from utils.logging.log_control import logger
from utils.thread.thread_data_control import threadLocalGlobalData
""" 测试相关操作 """
# 测试前导入测试数据进系统缓存
CaseDataControl.cases_data_import_process()
@pytest.fixture(scope="session", autouse=True)
def login_init():
"""
测试前获取登录信息
:return:
"""
""" OA系统 """
loginOaData = Login.oa(loginName=threadLocalGlobalData.configData['account']['oa']['username'],
password=threadLocalGlobalData.configData['account']['oa']['password'])
# token
SystemCacheHandler.set_cache(cacheName='loginOaToken', value=loginOaData['token'])
# cookie
cookies = ''
for k, v in loginOaData['cookies'].items():
cookie = k + "=" + v + ";"
# 拿到登录的cookie内容,cookie拿到的是字典类型,转换成对应的格式
cookies += cookie
# 将登录接口中的cookie写入缓存中,其中login_cookie是缓存名称
SystemCacheHandler.set_cache(cacheName='loginOaCookie', value=cookies)
""" 司机APP """
loginDriverData = Login.driver(userPhone=threadLocalGlobalData.configData['account']['driver']['userPhone'])
# token
SystemCacheHandler.set_cache(cacheName='loginDriverToken', value=loginDriverData['token'])
@pytest.fixture(scope='function')
def test_data(request):
""" 处理当前用例的测试数据 """
caseData = TestCaseModel(**request.param)
# 判断是否跳过当前测试用例
isRun = Sub.sub_all(caseData.isRun)
if isRun is False:
allure_title(caseData.detail)
allure_step(f'用例ID --> {caseData.caseId}')
allure_step(f"请求host: {caseData.host}")
allure_step(f"请求path: {caseData.path}")
allure_step(f"请求方式: {caseData.method}")
allure_step_text("请求头: ", caseData.headers)
allure_step_text("请求数据: ", caseData.requestPayload)
logger.info(f'当前用例 isRun 判断为:{isRun},跳过当前测试')
pytest.skip(f'当前用例 isRun 判断为:{isRun},跳过当前测试')
yield caseData
""" 自定义命令行参数 """
def pytest_addoption(parser):
"""
第一个参数表示option的缩写,以单个中划线引导,例如-f、-d,只能用单个字母,可以使用大写;
第二个参数表示option的全拼,以两个中划线引导,例如--file、--Opencv_version;
第一第二个参数可以单独使用,也可以同时使用,但必须保证有其中一个。
从第三个参数开始是命名参数,是可选参数,常用的几个:
action:在命令行中遇到此参数时要采取的基本操作类型;
nargs:应该使用的命令行参数的数量;
const:某些操作和nargs选择所需的常量值;
default:如果参数不在命令行中,则生成的默认值。
type:命令行参数应该转换为的类型;
choices:参数允许值的容器;
required:命令行选项是否可以省略(仅可选);
help:对参数作用的简要说明;
metavar:用法消息中参数的名称;
dest:要添加到 parse_args() 返回的对象中的属性的名称;
:param parser:
:return:
"""
parser.addoption('--flag-test', action='store_true', default=False,
help='只有两个值True和False,当用户不传flag参数时,默认为False,当用户传递flag时,值为True')
""" 获取命令行参数 """
# 通过fixture函数中的request参数去读取命令行传递的参数,赋值给一个变量,就可以在pytest中随便使用
@pytest.fixture(scope='session')
def get_flag_test(request):
return request.config.getoption('--flag-test')
""" hook函数 """
def pytest_report_teststatus(report, config):
"""
返回各个测试阶段的result, 可以用when属性来区分不同阶段
:param report:
:param config:
:return:
"""
""" 自定义测试结果 """
# 命令行执行pytest用例,默认情况下.代表通过的用例,F代表失败的用例,E代表异常的用例
# 将测试结果.自定义为√,F自定义为x,setup的error自定义为0,teardown的error自定义为1,跳过skipped自定义为 /
if report.when == 'call' and report.passed:
return report.outcome, '√ PASSED', 'passed'
if report.when == 'call' and report.failed:
return report.outcome, 'x FAILED', 'failed'
if report.when == 'setup' and report.failed:
return report.outcome, '0 SETUP ERROR', 'error'
if report.when == 'teardown' and report.failed:
return report.outcome, '1 TEARDOWN ERROR', 'error'
if report.skipped:
return report.outcome, '/ SKIPPED', 'skipped'
def pytest_runtest_setup(item):
"""
在pytest_runtest_call执行之前调用
:param item:
:return:
"""
logger.info(f'当前用例:{item}')
"""被标记的用例执行失败后,当前测试类中其他同样被标记的未执行用例不再执行"""
# 判断是否存在被标记的用例执行失败,如果存在则需要跳过其他被标记的用例
if 'failed_skip_other' in item.keywords:
logger.info(f'当前用例被failed_skip_other标记,检查当前用例的测试类中是否存在执行失败用例 <item.keywords:{item.keywords}> ')
cls_name = str(item.cls)
if cls_name in threadLocalGlobalData.test_failed_incremental:
logger.info(
f'存在执行失败用例 <cls_name:{cls_name}> <test_failed_incremental:{threadLocalGlobalData.test_failed_incremental}> ')
pytest.xfail(
f'当前用例的测试类中存在被failed_skip_other标记的执行失败用例,跳过当前测试类中其他同样被标记的未执行用例 -> 执行失败用例,测试类名:{cls_name},用例名称及其数据驱动执行序号:{threadLocalGlobalData.test_failed_incremental[cls_name]}')
else:
logger.info(
f'不存在执行失败用例,不跳过当前用例 <cls_name:{cls_name}> <test_failed_incremental:{threadLocalGlobalData.test_failed_incremental}> ')
@pytest.hookimpl(tryfirst=True, hookwrapper=True)
def pytest_runtest_makereport(item, call):
"""
pytest提供了pytest_runtest_makereport这个方法,可以捕获每个用例的执行情况
对于给定的测试用例(item)和调用步骤(call),返回一个对应的测试报告对象(_pytest.runner.TestReport)
具体表现为:这个钩子方法会被每个测试用例调用 3 次,分别是:
初始化环节setup:用例的 setup 执行完毕后,调用 1 次,返回 setup 的执行结果
用例执行环节call:用例执行完毕之后,调用 1 次,返回测试用例的执行结果
清理环节teardown:用例的 teardown 执行完毕后,调用1 次,返回 teardown 的执行结果
:param item: 测试用例对象
:param call: 测试用例的测试步骤
:return:
"""
# 获取钩子方法的调用结果
out = yield
# 从钩子方法的调用结果中获取测试报告
report = out.get_result()
logger.info(f'当前用例:{item},执行阶段:{report.when}')
# 检查当前用例执行的异常情况(执行跳过、执行失败、预期失败等)
if call.excinfo is not None:
logger.warning('执行结果:{}'.format(report.outcome))
logger.warning('执行信息:{}'.format(call.excinfo))
# 判断用例是否执行失败
if report.failed:
""" 用例执行情况 """
logger.error('---------------测试用例失败---------------')
logger.error(f'\n=======================================================================\n'
f'report所有参数:{report.__dict__}\n'
f'=======================================================================')
logger.error('测试用例:{}'.format(item))
logger.error('用例描述:{}'.format(item.function.__doc__))
logger.error('执行阶段:{}'.format(report.when))
logger.error('异常结果:{}'.format(call.excinfo))
logger.error('测试结果:{}'.format(report.outcome))
logger.error('用例耗时:{}'.format(report.duration))
""" 被标记的用例执行失败后,当前测试类中其他同样被标记的未执行用例不再执行 """
# 在执行用例时,遇到用例之前存在有关联,用例执行失败后,其余用例也没有必要再去执行(比如:登录失败后,我的列表、我的订单等用例就没有比必要执行了)
# 在每个测试用例执行之前,判断当前用例所在的类是否有失败的用例,如果有就使用pytest.xfail标记为预期失败的用例,不再执行
# 实现步骤:
# 1.定义一个失败用例增量集(全局变量)
# 2.自定一个mark标记,将用例之间有耦合性的用例标记出来(可以通过这个来控制是否需要)
# 3.添加失败用例:用 "pytest_runtest_makereport" 函数中使用call中的excinfo信息判断用例是否失败,如果失败就将用例添加到失败用例增量集(全局变量)中
# 4.在用例执行前判断是否有失败用例:用 "pytest_runtest_setup" 函数中实现判断当前用例所在的类是否有失败的用例
# 使用方式:在测试用例上使用修饰器 @pytest.mark.failed_skip_other
# 判断执行失败用例是否被标记,如果是则添加到失败用例增量集(全局变量)中
if 'failed_skip_other' in item.keywords:
cls_name = str(item.cls)
# 判断当前用例是否使用了数据驱动,如果存在则获取其执行的序号,不存在则默认为()
parametrize_index = (
tuple(item.callspec.indices.values())
if hasattr(item, 'callspec')
else ()
)
test_name = item.originalname or item.name
threadLocalGlobalData.test_failed_incremental.setdefault(cls_name, {test_name: parametrize_index})
logger.debug(f'用例类名:{cls_name}')
logger.debug(f'用例名称:{test_name}')
logger.debug(f'执行序号:{parametrize_index}')
logger.info(
f'当前用例被failed_skip_other标记,添加到失败用例增量集(全局变量)中 <test_failed_incremental:{threadLocalGlobalData.test_failed_incremental}>')
def pytest_collection_modifyitems(session, config, items) -> None:
"""
在用例收集完毕之后被调用,可以用来调整测试用例执行顺序
:param session: 会话对象
:param config: 配置对象
:param items: 用例对象列表;改变items里面用例的顺序就可以改变用例的执行顺序了
:return:
"""
"""解决parametrize中ids里包含中文时显示为unicode编码问题"""
for item in items:
item.name = item.name.encode('utf-8').decode('unicode-escape')
item._nodeid = item.nodeid.encode('utf-8').decode('unicode-escape')
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/panyurong/api_auto_frame_public.git
git@gitee.com:panyurong/api_auto_frame_public.git
panyurong
api_auto_frame_public
api_auto_frame_public
master

搜索帮助