更新依赖文件,兼容新pytest-html写法,增加抛出异常类型

This commit is contained in:
wangjie 2023-08-18 18:40:00 +08:00
parent 895d9f8831
commit 890fd803ab
9 changed files with 84 additions and 98 deletions

View File

@ -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:

View File

@ -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):
"""断开数据库连接"""

View File

@ -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__':

View File

@ -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'))

View File

@ -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

View File

@ -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
View File

@ -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: # 判断是否需要发送企业微信

View File

@ -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

View File

@ -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'))