更新依赖文件,兼容新pytest-html写法,增加抛出异常类型
This commit is contained in:
parent
895d9f8831
commit
890fd803ab
|
@ -15,6 +15,7 @@ from requests import PreparedRequest
|
|||
from requests.structures import CaseInsensitiveDict
|
||||
|
||||
from common.base_log import logger
|
||||
from common.exceptions import ValueNotFoundError
|
||||
from configs.lins_environment import EntryPoint
|
||||
from utils.time_utils import TimeUtil
|
||||
|
||||
|
@ -121,7 +122,7 @@ class BaseApi:
|
|||
json_data = response.json()
|
||||
return json_data
|
||||
else:
|
||||
raise Exception('请求返回结果为空')
|
||||
raise ValueNotFoundError('请求返回结果为空,无法获取响应')
|
||||
|
||||
@staticmethod
|
||||
def get_text(response: requests.Response) -> str:
|
||||
|
|
|
@ -30,6 +30,7 @@ class Postgresql:
|
|||
logger.info("数据库连接成功")
|
||||
except psycopg2.Error as e:
|
||||
logger.error(f"连接数据库错误: {e}")
|
||||
raise
|
||||
|
||||
def execute_sql(self, sql):
|
||||
"""
|
||||
|
@ -68,7 +69,6 @@ class Postgresql:
|
|||
return results
|
||||
except psycopg2.Error as e:
|
||||
logger.error(f"执行sql错误: {e}")
|
||||
return None
|
||||
finally:
|
||||
if conn:
|
||||
self.pool.putconn(conn) # 将连接归还到连接池
|
||||
|
@ -113,6 +113,7 @@ class MySQL:
|
|||
logger.info("数据库连接成功")
|
||||
except pymysql.Error as e:
|
||||
logger.error(f"连接数据库错误: {e}")
|
||||
raise
|
||||
|
||||
def execute_sql(self, sql):
|
||||
"""
|
||||
|
@ -146,7 +147,6 @@ class MySQL:
|
|||
return results
|
||||
except psycopg2.Error as e:
|
||||
logger.error(f"执行sql错误: {e}")
|
||||
return None
|
||||
|
||||
def disconnect(self):
|
||||
"""断开数据库连接"""
|
||||
|
|
|
@ -10,6 +10,7 @@ from email.mime.application import MIMEApplication
|
|||
from email.mime.multipart import MIMEMultipart
|
||||
from email.mime.text import MIMEText
|
||||
from common.base_log import logger
|
||||
from common.exceptions import SendMessageError
|
||||
|
||||
|
||||
class MailSender:
|
||||
|
@ -91,8 +92,10 @@ class MailSender:
|
|||
logger.info("发送邮件成功")
|
||||
except smtplib.SMTPException as e:
|
||||
logger.error("Error: 无法发送邮件,失败原因:{}".format(e))
|
||||
raise SendMessageError(f'发送电子邮件时发生错误:{e}')
|
||||
except Exception as e:
|
||||
logger.error("Error: 无法发送邮件,失败原因:{}".format(e))
|
||||
raise
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
59
conftest.py
59
conftest.py
|
@ -4,14 +4,12 @@
|
|||
# @Author : wangjie
|
||||
# @File : conftest.py
|
||||
# @project : SensoroApi
|
||||
import json
|
||||
import os.path
|
||||
import platform
|
||||
import shutil
|
||||
import time
|
||||
|
||||
import pytest
|
||||
from py.xml import html
|
||||
|
||||
from common.settings import ENV
|
||||
from configs.dir_path_config import BASE_DIR
|
||||
|
@ -37,14 +35,14 @@ def pytest_sessionstart():
|
|||
def pytest_sessionfinish(session, exitstatus):
|
||||
"""运行完成后生成allure报告文件,再将本地启动方式放入该目录下"""
|
||||
# # allure报告展示environment时所需要的数据,这里是在项目根路径下创建的environment.properties文件拷贝到allure-report报告中,保证环境文件不会被清空
|
||||
# shutil.copy(BASE_DIR + '/environment.properties', BASE_DIR + '/Temp/environment.properties')
|
||||
# FileHandle.copy_file(BASE_DIR + os.sep + 'environment.properties', TEMP_DIR)
|
||||
# # allure报告展示运行器时所需要的数据
|
||||
# shutil.copy(BASE_DIR + '/executor.json', BASE_DIR + '/Temp/executor.json')
|
||||
# FileHandle.copy_file(BASE_DIR + os.sep + 'executor.json', TEMP_DIR)
|
||||
# # 使用allure generate -o 命令将./Temp目录下的临时报告生成到Report目录下变成html报告
|
||||
# os.system(f'allure generate {BASE_DIR}/Temp -o {BASE_DIR}/outFiles/allure_report --clean')
|
||||
# os.system(f'allure generate {TEMP_DIR} -o {ALLURE_REPORT_DIR} --clean')
|
||||
# # 将本地启动脚本和查看allure报告方法放入报告目录下面
|
||||
# shutil.copy(BASE_DIR + '/open_report.sh', BASE_DIR + '/outFiles/allure_report/open_report.sh')
|
||||
# shutil.copy(BASE_DIR + '/查看allure报告方法', BASE_DIR + '/outFiles/allure_report/查看allure报告方法')
|
||||
# FileHandle.copy_file(BASE_DIR + os.sep + 'open_report.sh', ALLURE_REPORT_DIR)
|
||||
# FileHandle.copy_file(BASE_DIR + os.sep + '查看allure报告方法', ALLURE_REPORT_DIR)
|
||||
|
||||
|
||||
def pytest_collection_modifyitems(items) -> None:
|
||||
|
@ -58,46 +56,41 @@ def pytest_collection_modifyitems(items) -> None:
|
|||
|
||||
def pytest_configure(config):
|
||||
"""修改pytest-html报告中Environment项目展示的信息"""
|
||||
pass
|
||||
|
||||
|
||||
def pytest_metadata(metadata: dict):
|
||||
"""修改pytest的metadata数据,在pytest-html报告中体现在Environment展示的信息"""
|
||||
# 添加项目名称
|
||||
# config._metadata["项目名称"] = "lins接口自动化测试"
|
||||
# 删除Java_Home
|
||||
# config._metadata.pop("JAVA_HOME")
|
||||
metadata['项目名称'] = 'lins接口自动化测试'
|
||||
# 删除Java_Home信息
|
||||
metadata.pop("JAVA_HOME")
|
||||
# 删除Plugins
|
||||
# config._metadata.pop("Plugins")
|
||||
# metadata.pop("Plugins")
|
||||
|
||||
|
||||
@pytest.mark.optionalhook
|
||||
@pytest.hookimpl(optionalhook=True)
|
||||
def pytest_html_results_summary(prefix):
|
||||
"""修改pytest-html报告中添加summary内容"""
|
||||
prefix.extend([html.p("所属部门: 测试组")])
|
||||
prefix.extend([html.p("测试人员: 汪杰")])
|
||||
prefix.extend(["<p>所属部门: 测试组</p>"])
|
||||
prefix.extend(["<p>测试人员: 汪杰</p>"])
|
||||
|
||||
|
||||
@pytest.mark.optionalhook
|
||||
@pytest.hookimpl(optionalhook=True)
|
||||
def pytest_html_results_table_header(cells):
|
||||
"""pytest-html报告中表头添加Description"""
|
||||
cells.insert(1, html.th('Description')) # 表头添加Description
|
||||
cells.insert(1, "<th>Description</th>") # 表头添加Description
|
||||
cells.pop(-1) # 删除link
|
||||
|
||||
|
||||
@pytest.mark.optionalhook
|
||||
@pytest.hookimpl(optionalhook=True)
|
||||
def pytest_html_results_table_row(report, cells):
|
||||
"""修改pytest-html报告中表头Description对应的内容为测试用例的描述"""
|
||||
cells.insert(1, html.td(report.description)) # 表头对应的内容
|
||||
cells.insert(1, f"<td>{report.description}</td>") # 表头对应的内容
|
||||
cells.pop(-1) # 删除link列
|
||||
|
||||
|
||||
# 收集用例
|
||||
pytest_result = {
|
||||
"case_pass": 0,
|
||||
"case_fail": 0,
|
||||
"case_skip": 0,
|
||||
"case_error": 0,
|
||||
"case_count": 0
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.hookwrapper
|
||||
@pytest.hookimpl(hookwrapper=True)
|
||||
def pytest_runtest_makereport(item, call): # description取值为用例说明__doc__
|
||||
"""获取测试结果、生成测试报告"""
|
||||
outcome = yield
|
||||
|
@ -121,11 +114,3 @@ def pytest_terminal_summary(terminalreporter, exitstatus, config):
|
|||
print(f"用例通过率:{pytest_result['pass_rate']}%")
|
||||
print(f"用例执行时间:{pytest_result['case_duration']}s")
|
||||
print(f"总用时(算上了生成报告的时间):{run_time}s")
|
||||
|
||||
|
||||
# @pytest.mark.optionalhook
|
||||
# def pytest_html_results_table_html(report, data):
|
||||
# """"pytest-html报告中清除执行成功的用例logs"""
|
||||
# if report.passed:
|
||||
# del data[:]
|
||||
# data.append(html.div('pass用例不展示日志', class_='empty log'))
|
||||
|
|
|
@ -2,4 +2,4 @@ OperatingEnvironment=TEST
|
|||
BaseUrl=https://www.wanandroid.com
|
||||
PythonVersion=3.10.4
|
||||
Platform=macOS-12.3.1-arm64-arm-64bit
|
||||
PytestVersion=7.1.2
|
||||
PytestVersion=7.4.0
|
||||
|
|
|
@ -1,19 +1,42 @@
|
|||
pytest==7.1.2
|
||||
PyYAML==6.0
|
||||
requests==2.27.1
|
||||
allure-pytest==2.13.2
|
||||
allure-python-commons==2.13.2
|
||||
annotated-types==0.5.0
|
||||
attrs==23.1.0
|
||||
certifi==2023.7.22
|
||||
cffi==1.15.1
|
||||
charset-normalizer==3.2.0
|
||||
colorlog==6.7.0 # 控制日志颜色的包
|
||||
cryptography==41.0.3 # 在使用MySQL8.0的SHA256密码或缓存SHA2密码身份验证时依赖的包
|
||||
DBUtils==3.0.3 # 是Python的一个用于实现数据库连接池的模块
|
||||
et-xmlfile==1.1.0
|
||||
exceptiongroup==1.1.3
|
||||
Faker==19.3.0 # 用于生成伪造数据的Python库l
|
||||
idna==3.4
|
||||
iniconfig==2.0.0
|
||||
Jinja2==3.1.2
|
||||
MarkupSafe==2.1.3
|
||||
openpyxl==3.1.2 # 操作excel的库
|
||||
packaging==23.1
|
||||
pluggy==1.2.0
|
||||
psycopg2-binary==2.9.7 # 用于链接PostgreSQL数据库的包
|
||||
py3curl==1.1.3 # 自己写的一个Python库,它可以将Python中的requests请求转换为cURL命令,方便开发人员在终端中进行调试和测试。
|
||||
allure-pytest==2.9.45
|
||||
pytest_ordering==0.6 #pytest控制用例执行顺序的包
|
||||
pytest-dependency # 控制pytest用例依赖的包
|
||||
pytest-rerunfailures==10.2 # 控制pytest用例失败重跑的插件
|
||||
pytest-html==3.1.1 # pytest展示报告
|
||||
psycopg2-binary==2.9.6 # 用于链接PostgreSQL数据库的包
|
||||
pymysql==1.0.3
|
||||
DBUtils==3.0.2 # 是Python的一个用于实现数据库连接池的模块
|
||||
cryptography==40.0.2 # 在使用MySQL8.0的SHA256密码或缓存SHA2密码身份验证时依赖的包
|
||||
pytest-sugar==0.9.7 # pytest测试用例显示进度条的包
|
||||
pytest-json-report==1.5.0 # pytest生成json格式的报告
|
||||
colorlog==6.7.0 # 控制日志颜色的包
|
||||
pydantic==2.0.1 # 用于数据验证和序列化的Python库
|
||||
openpyxl==3.1.2 # 操作excel的库
|
||||
Faker==19.2.0 # 用于生成伪造数据的Python库
|
||||
pycparser==2.21
|
||||
pydantic==2.1.1 # 用于数据验证和序列化的Python库
|
||||
pydantic_core==2.4.0
|
||||
PyMySQL==1.1.0
|
||||
pytest==7.4.0
|
||||
pytest-dependency==0.5.1 # 控制pytest用例依赖的包
|
||||
pytest-html==4.0.0rc6 # pytest展示报告
|
||||
pytest-json-report==1.5.0 # pytest生成json格式的报告
|
||||
pytest-metadata==3.0.0
|
||||
pytest-ordering==0.6 #pytest控制用例执行顺序的包
|
||||
pytest-rerunfailures==12.0 # 控制pytest用例失败重跑的插件
|
||||
pytest-sugar==0.9.7 # pytest测试用例显示进度条的包
|
||||
python-dateutil==2.8.2
|
||||
PyYAML==6.0.1
|
||||
requests==2.31.0
|
||||
six==1.16.0
|
||||
termcolor==2.3.0
|
||||
tomli==2.0.1
|
||||
typing_extensions==4.7.1
|
||||
urllib3==2.0.4
|
10
run.py
10
run.py
|
@ -10,7 +10,6 @@
|
|||
"""
|
||||
|
||||
import os
|
||||
import shutil
|
||||
|
||||
import pytest
|
||||
|
||||
|
@ -21,6 +20,7 @@ from common.robot_sender import EnterpriseWechatNotification
|
|||
from common.settings import IS_SEND_EMAIL, IS_SEND_WECHAT
|
||||
from configs.dir_path_config import BASE_DIR, TEMP_DIR, ALLURE_REPORT_DIR, PYTEST_REPORT_DIR, CONFIGS_DIR, \
|
||||
PYTEST_RESULT_DIR
|
||||
from utils.file_handle import FileHandle
|
||||
from utils.yaml_handle import YamlHandle
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
@ -57,14 +57,14 @@ if __name__ == '__main__':
|
|||
|
||||
###################发送allure报告
|
||||
# allure报告展示environment时所需要的数据,这里是在项目根路径下创建的environment.properties文件拷贝到allure-report报告中,保证环境文件不会被清空
|
||||
shutil.copy(BASE_DIR + os.sep + 'environment.properties', TEMP_DIR + os.sep + 'environment.properties')
|
||||
FileHandle.copy_file(BASE_DIR + os.sep + 'environment.properties', TEMP_DIR)
|
||||
# allure报告展示运行器时所需要的数据
|
||||
shutil.copy(BASE_DIR + os.sep + 'executor.json', TEMP_DIR + os.sep + 'executor.json')
|
||||
FileHandle.copy_file(BASE_DIR + os.sep + 'executor.json', TEMP_DIR)
|
||||
# 使用allure generate -o 命令将./Temp目录下的临时报告生成到Report目录下变成html报告
|
||||
os.system(f'allure generate {TEMP_DIR} -o {ALLURE_REPORT_DIR} --clean')
|
||||
# 将本地启动脚本和查看allure报告方法放入报告目录下面
|
||||
shutil.copy(BASE_DIR + os.sep + 'open_report.sh', ALLURE_REPORT_DIR + os.sep + 'open_report.sh')
|
||||
shutil.copy(BASE_DIR + os.sep + '查看allure报告方法', ALLURE_REPORT_DIR + os.sep + '查看allure报告方法')
|
||||
FileHandle.copy_file(BASE_DIR + os.sep + 'open_report.sh', ALLURE_REPORT_DIR)
|
||||
FileHandle.copy_file(BASE_DIR + os.sep + '查看allure报告方法', ALLURE_REPORT_DIR)
|
||||
|
||||
# 发送企业微信群聊
|
||||
if IS_SEND_WECHAT: # 判断是否需要发送企业微信
|
||||
|
|
|
@ -9,13 +9,10 @@ import platform
|
|||
|
||||
import allure
|
||||
import pytest
|
||||
from py.xml import html
|
||||
|
||||
from common.base_api import BaseApi
|
||||
from common.base_log import logger
|
||||
from common.exceptions import ValueNotFoundError
|
||||
from common.settings import ENV
|
||||
from configs.dir_path_config import BASE_DIR
|
||||
from pageApi.login import Login
|
||||
|
||||
# 定义一个全局变量,用于存储提取的参数内容
|
||||
|
@ -51,7 +48,7 @@ def get_global_data():
|
|||
allure.attachment_type.TEXT)
|
||||
return _global_data[cache_data]
|
||||
except KeyError:
|
||||
allure.attach(str(_global_data), '当前可使用的全局变量:', allure.attachment_type.TEXT)
|
||||
allure.attach(str(_global_data), '获取变量失败,当前可使用的全局变量:', allure.attachment_type.TEXT)
|
||||
raise ValueNotFoundError(f"{cache_data}的缓存数据未找到,请检查是否将该数据存入缓存中")
|
||||
|
||||
return _get_global_data
|
||||
|
@ -61,27 +58,8 @@ def get_global_data():
|
|||
def get_token():
|
||||
"""获取登录V1的token"""
|
||||
logger.info("开始用例前置操作")
|
||||
# 登录前需要先获取验证码
|
||||
Login().get_sendSms('13800000111')
|
||||
# 调登录接口,获取登录接口的token¬
|
||||
login_response = Login().login_v1('13800000111', '123456')
|
||||
login_response = Login().login('18800000001', '123456')
|
||||
token = BaseApi.get_json(login_response)['data']['token']
|
||||
logger.info("结束用例前置操作")
|
||||
return token
|
||||
|
||||
|
||||
@pytest.fixture(scope="session", autouse=False)
|
||||
def get_token_v2():
|
||||
"""获取登录V2的Ai视频管理项目的token"""
|
||||
logger.info("开始用例前置操作")
|
||||
# 登录前需要先获取验证码
|
||||
Login().get_sendSms('13800000111')
|
||||
# 调登录接口,获取登录接口的token
|
||||
login_response = Login().login_app_v2('13800000111', '123456')
|
||||
login_token = BaseApi.get_json(login_response)['data']['token']
|
||||
# 调切换租户的接口,获取切换到指定租户的token
|
||||
headers = {'Authorization': f'Bearer {login_token}'}
|
||||
res = Login().select_tenant(tenantId='1622903542623612930', projectId='1622903550156582913', headers=headers)
|
||||
token = BaseApi.get_json(res)['data']['token']
|
||||
logger.info("结束用例前置操作")
|
||||
return token
|
||||
|
|
|
@ -121,23 +121,17 @@ class FileHandle:
|
|||
"""
|
||||
复制一个文件到另一个目录
|
||||
:param: src_file_path: 源文件路径
|
||||
:param: dest_dir_path: 目标文件夹路径
|
||||
:param: dest_dir_path: 目标文件夹路径或文件路径,不写文件名则保持源文件名,写了则重命名
|
||||
|
||||
"""
|
||||
# 判断源文件路径是否存在
|
||||
if not os.path.isfile(src_file_path):
|
||||
return "源文件路径不存在"
|
||||
|
||||
# 判断目标文件夹路径是否存在,不存在则创建
|
||||
if not os.path.isdir(dest_dir_path):
|
||||
os.makedirs(dest_dir_path)
|
||||
|
||||
raise FileNotFoundError(f"源文件路径不存在:{src_file_path}")
|
||||
# 复制文件
|
||||
try:
|
||||
shutil.copy(src_file_path, dest_dir_path)
|
||||
print("复制成功")
|
||||
except Exception as e:
|
||||
raise f"复制失败:{e}"
|
||||
raise
|
||||
|
||||
@staticmethod
|
||||
def get_file_field(file_path):
|
||||
|
@ -164,5 +158,7 @@ class FileHandle:
|
|||
relative_path = os.path.relpath(os.path.abspath(file_path), os.path.abspath(directory_path))
|
||||
# 如果相对路径中包含文件名,则去除文件名部分并返回
|
||||
return os.path.dirname(relative_path)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
print(FileHandle.get_files('/Users/wangjie/SensoroApi/configs'))
|
||||
print(FileHandle.get_files('/Users/wangjie/SensoroApi/configs'))
|
||||
|
|
Loading…
Reference in New Issue