增加allure报告优化类,allure报告增加步骤信息

This commit is contained in:
wangjie 2023-09-27 20:18:56 +08:00
parent 5f3808d8f5
commit fffc80efc2
9 changed files with 264 additions and 74 deletions

View File

@ -7,8 +7,9 @@
import base64
import json
import time
from typing import Optional, Tuple, Dict, Any
from typing import Optional, Tuple, Any
import allure
import py3curl
import requests
from requests import PreparedRequest
@ -17,6 +18,7 @@ from requests.structures import CaseInsensitiveDict
from common.base_log import logger
from common.exceptions import ValueNotFoundError
from configs.lins_environment import EntryPoint
from utils.allure_handle import allure_attach_text, allure_attach_json
from utils.time_utils import TimeUtil
@ -64,7 +66,7 @@ class BaseApi:
return params
@staticmethod
def request(method, address, headers=None, params=None, data=None, json=None, files=None) -> requests.Response:
def request(method, address, headers=None, params=None, data=None, json_data=None, files=None) -> requests.Response:
"""发送http请求返回response对象"""
# 处理请求参数
url = BaseApi._make_url(address)
@ -76,20 +78,41 @@ class BaseApi:
start_time = time.time() # 记录请求开始时间
# 发起请求
response = requests.request(method=method, url=url, headers=headers, params=params,
data=data, json=json, files=files)
data=data, json=json_data, files=files)
end_time = time.time() # 记录请求结束时间
elapsed_time = end_time - start_time # 计算请求时长
duration = end_time - start_time # 计算请求时长
# 记录请求时的详情信息
r_uri = response.request.url
r_method = method.upper()
r_headers = response.request.headers
r_body = BaseApi.get_request_body(response)
r_curl = BaseApi.request_to_curl(response)
r_respone = response.json()
r_duration = duration
r_respone_status_code = response.status_code
r_respone_headers = response.headers
_log_msg = f"\n==================================================\n" \
f"请求路径:{response.request.url}\n" \
f"请求方式:{method.upper()}\n" \
f"请求头:{response.request.headers}\n" \
f"请求内容:{BaseApi.get_request_body(response)}\n" \
f"请求curl命令{BaseApi.request_to_curl(response)}\n" \
f"接口响应内容:{response.json()}\n" \
f"接口响应时长:{elapsed_time:.2f}\n" \
f"HTTP状态码{response.status_code}\n" \
f"请求路径:{r_uri}\n" \
f"请求方式:{r_method}\n" \
f"请求头:{r_headers}\n" \
f"请求内容:{r_body}\n" \
f"请求curl命令{r_curl}\n" \
f"接口响应内容:{r_respone}\n" \
f"接口响应头:{r_respone_headers}\n" \
f"接口响应时长:{r_duration:.2f}\n" \
f"HTTP状态码{r_respone_status_code}\n" \
f"=================================================="
with allure.step("请求内容"):
allure_attach_text("请求路径", f"{r_uri}")
allure_attach_text("请求方式", f"{r_method}")
allure_attach_text("请求头", f"{r_headers}")
allure_attach_json("请求体", f"{r_body}")
allure_attach_text("请求curl命令", f"{r_curl}")
with allure.step("响应内容"):
allure_attach_json("响应体", f"{json.dumps(r_respone, ensure_ascii=False, indent=4)}")
allure_attach_text("HTTP状态码", f"{r_respone_status_code}")
allure_attach_text("响应头", f"{r_respone_headers}")
if response.status_code == 200:
logger.info(_log_msg)
else:
@ -107,19 +130,22 @@ class BaseApi:
return BaseApi.request(method='get', address=address, params=params, headers=headers)
@staticmethod
def post(address, data=None, json=None, headers=None, files=None) -> requests.Response:
def post(address, data=None, json_data=None, headers=None, files=None) -> requests.Response:
"""发送post请求返回response对象"""
return BaseApi.request(method='post', address=address, data=data, json=json, headers=headers, files=files)
return BaseApi.request(method='post', address=address, data=data, json_data=json_data, headers=headers,
files=files)
@staticmethod
def delete(address, data=None, json=None, headers=None, files=None) -> requests.Response:
"""发送delete请求返回response对象"""
return BaseApi.request(method='delete', address=address, data=data, json=json, headers=headers, files=files)
return BaseApi.request(method='delete', address=address, data=data, json_data=json, headers=headers,
files=files)
@staticmethod
def put(address, data=None, json=None, headers=None, files=None) -> requests.Response:
def put(address, data=None, json_data=None, headers=None, files=None) -> requests.Response:
"""发送put请求返回response对象"""
return BaseApi.request(method='put', address=address, data=data, json=json, headers=headers, files=files)
return BaseApi.request(method='put', address=address, data=data, json_data=json_data, headers=headers,
files=files)
@staticmethod
def get_json(response: requests.Response) -> json:

View File

@ -5,7 +5,7 @@
# @File : models.py
# @project : SensoroApi
from dataclasses import dataclass
from enum import Enum
from enum import Enum, unique
from typing import Text
@ -34,3 +34,33 @@ class TestMetrics:
if __name__ == '__main__':
print(Environment.DEV.name)
print(Environment.DEV.value)
@unique # 枚举类装饰器,确保只有一个名称绑定到任何一个值。
class AllureAttachmentType(Enum):
"""
allure 报告的文件类型枚举
"""
TEXT = "txt"
CSV = "csv"
TSV = "tsv"
URI_LIST = "uri"
HTML = "html"
XML = "xml"
JSON = "json"
YAML = "yaml"
PCAP = "pcap"
PNG = "png"
JPG = "jpg"
SVG = "svg"
GIF = "gif"
BMP = "bmp"
TIFF = "tiff"
MP4 = "mp4"
OGG = "ogg"
WEBM = "webm"
PDF = "pdf"

View File

@ -4,45 +4,22 @@
# @Author : wangjie
# @File : conftest.py
# @project : SensoroApi
import os.path
import platform
import time
import pytest
from common.models import TestMetrics
from common.settings import ENV
from configs.dir_path_config import BASE_DIR
from configs.lins_environment import EntryPoint
from utils.report_data_handle import ReportDataHandle
def pytest_sessionstart():
"""在整个pytest运行过程开始之前设置allure报告的环境变量信息"""
allure_env = {
'OperatingEnvironment': ENV.name,
'BaseUrl': EntryPoint.URL(),
'PythonVersion': platform.python_version(),
'Platform': platform.platform(),
'PytestVersion': pytest.__version__,
}
allure_env_file = os.path.join(BASE_DIR, 'environment.properties')
with open(allure_env_file, 'w', encoding='utf-8') as f:
for _k, _v in allure_env.items():
f.write(f'{_k}={_v}\n')
"""在整个pytest运行过程开始之前执行的操作"""
pass
def pytest_sessionfinish(session, exitstatus):
"""运行完成后生成allure报告文件再将本地启动方式放入该目录下"""
# # allure报告展示environment时所需要的数据这里是在项目根路径下创建的environment.properties文件拷贝到allure-report报告中,保证环境文件不会被清空
# FileHandle.copy_file(BASE_DIR + os.sep + 'environment.properties', TEMP_DIR)
# # allure报告展示运行器时所需要的数据
# 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报告方法放入报告目录下面
# FileHandle.copy_file(BASE_DIR + os.sep + 'open_report.sh', ALLURE_REPORT_DIR)
# FileHandle.copy_file(BASE_DIR + os.sep + '查看allure报告方法', ALLURE_REPORT_DIR)
"""在整个pytest session结束后执行的操作"""
pass
def pytest_collection_modifyitems(items) -> None:

View File

@ -1,5 +0,0 @@
OperatingEnvironment=TEST
BaseUrl=https://www.wanandroid.com
PythonVersion=3.10.4
Platform=macOS-12.3.1-arm64-arm-64bit
PytestVersion=7.4.0

View File

@ -1,10 +0,0 @@
{
"name": "汪杰",
"type": "jenkins",
"url": "http://helloqa.com",
"buildOrder": 3,
"buildName": "allure-report_deploy#1",
"buildUrl": "http://helloqa.com#1",
"reportUrl": "http://helloqa.com#1/AllureReport",
"reportName": "汪杰 Allure Report"
}

View File

@ -15,7 +15,7 @@ class Login(BaseApi):
'password': password
}
return self.post(address, json=json)
return self.post(address, json_data=json)
if __name__ == '__main__':

16
run.py
View File

@ -16,6 +16,7 @@ import pytest
from common.base_log import logger
from common.models import TestMetrics
from utils.allure_handle import AllureReportBeautiful
from utils.command_parser import command_parser
from common.mail_sender import MailSender
from common.robot_sender import EnterpriseWechatNotification
@ -58,17 +59,22 @@ if __name__ == '__main__':
# '-m smoke', # 只运行mark标记为smoke的测试用例
])
###################发送allure报告
# allure报告展示environment时所需要的数据这里是在项目根路径下创建的environment.properties文件拷贝到allure-report报告中,保证环境文件不会被清空
FileHandle.copy_file(BASE_DIR + os.sep + 'environment.properties', TEMP_DIR)
# allure报告展示运行器时所需要的数据
FileHandle.copy_file(BASE_DIR + os.sep + 'executor.json', TEMP_DIR)
# ------------------------------发送allure报告----------------------------------
# 生成allure报告环境信息
AllureReportBeautiful.set_report_env_on_results()
# 生成allure报告执行器信息
AllureReportBeautiful.set_report_executer_on_results()
# 使用allure generate -o 命令将./Temp目录下的临时报告生成到Report目录下变成html报告
os.system(f'allure generate {TEMP_DIR} -o {ALLURE_REPORT_DIR} --clean')
# 修改allure报告浏览器窗口标题
AllureReportBeautiful.set_windows_title("Sensoro自动化")
# 修改allure报告标题
AllureReportBeautiful.set_report_name("Sensoro自动化测试报告")
# 将本地启动脚本和查看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)
# ------------------------------发送通知消息----------------------------------
# 发送企业微信群聊
pytest_result = asdict(TestMetrics(**ReportDataHandle.pytest_json_report_case_count()))
if IS_SEND_WECHAT: # 判断是否需要发送企业微信

View File

@ -4,9 +4,6 @@
# @Author : wangjie
# @File : conftest.py
# @project : SensoroApi
import os.path
import platform
import allure
import pytest
@ -14,6 +11,7 @@ from common.base_api import BaseApi
from common.base_log import logger
from common.exceptions import ValueNotFoundError
from pageApi.login import Login
from utils.allure_handle import allure_attach_text
# 定义一个全局变量,用于存储提取的参数内容
_global_data = {}
@ -28,8 +26,9 @@ def set_global_data():
def _set_global_data(cache_name, value):
_global_data[cache_name] = value
allure.attach(str(f"'{cache_name}':'{value}'"), '设置变量:', allure.attachment_type.TEXT)
allure.attach(str(_global_data), '当前可使用的全局变量:', allure.attachment_type.TEXT)
with allure.step("提取"):
allure_attach_text("设置变量", str(f"'{cache_name}':'{value}'"))
allure_attach_text("当前可使用的全局变量", str(_global_data))
yield _set_global_data
_global_data.clear()
@ -44,11 +43,12 @@ def get_global_data():
def _get_global_data(cache_data):
try:
allure.attach(str(f"{cache_data}:{_global_data.get(cache_data, None)}"), '取出来的变量:',
allure.attachment_type.TEXT)
with allure.step("提取"):
allure_attach_text("取出来的变量", str(f"{cache_data}:{_global_data.get(cache_data, None)}"))
return _global_data[cache_data]
except KeyError:
allure.attach(str(_global_data), '获取变量失败,当前可使用的全局变量:', allure.attachment_type.TEXT)
with allure.step("获取变量失败,当前可使用的全局变量"):
allure_attach_text("获取变量失败,当前可使用的全局变量", str(_global_data))
raise ValueNotFoundError(f"{cache_data}的缓存数据未找到,请检查是否将该数据存入缓存中")
return _get_global_data

166
utils/allure_handle.py Normal file
View File

@ -0,0 +1,166 @@
# !/usr/bin/python
# -*- coding:utf-8 -*-
# @Time : 2023/9/27 20:05
# @Author : wangjie
# @File : allure_handle.py
# @project : SensoroApiAutoTest
import json
import os
import platform
import allure
import pytest
from common.models import AllureAttachmentType
from common.settings import ENV
from configs.dir_path_config import TEMP_DIR, ALLURE_REPORT_DIR
from configs.lins_environment import EntryPoint
def allure_title(title: str) -> None:
"""allure中动态生成用例标题"""
# allure.dynamic动态属性
allure.dynamic.title(title)
def allure_attach_text(name: str, body: str = None) -> None:
"""
allure报告添加文本格式附件
:param name: 附件名称
:param body: 附件内容
:return:
"""
allure.attach(body=body, name=name, attachment_type=allure.attachment_type.TEXT)
def allure_attach_json(name: str, body: str = None) -> None:
"""
allure报告添加json格式附件
:param name: 附件名称
:param body: 附件内容
:return:
"""
allure.attach(body=body, name=name, attachment_type=allure.attachment_type.JSON)
def allure_attach_file(name: str, source: str):
"""
allure报告上传附件图片excel等
:param name: 名称
:param source: 文件路径相当于传一个文件
:return:
"""
# 获取上传附件的尾缀,判断对应的 attachment_type 枚举值
_name = source.split('.')[-1]
if _name == "txt" or _name == "uri":
_name = "text" if _name == "txt" else "uri_list"
attachment_type_mapping = {
AllureAttachmentType.TEXT: allure.attachment_type.TEXT,
AllureAttachmentType.CSV: allure.attachment_type.CSV,
AllureAttachmentType.TSV: allure.attachment_type.TSV,
AllureAttachmentType.URI_LIST: allure.attachment_type.URI_LIST,
AllureAttachmentType.HTML: allure.attachment_type.HTML,
AllureAttachmentType.XML: allure.attachment_type.XML,
AllureAttachmentType.JSON: allure.attachment_type.JSON,
AllureAttachmentType.YAML: allure.attachment_type.YAML,
AllureAttachmentType.PCAP: allure.attachment_type.PCAP,
AllureAttachmentType.PNG: allure.attachment_type.PNG,
AllureAttachmentType.JPG: allure.attachment_type.JPG,
AllureAttachmentType.SVG: allure.attachment_type.SVG,
AllureAttachmentType.GIF: allure.attachment_type.GIF,
AllureAttachmentType.BMP: allure.attachment_type.BMP,
AllureAttachmentType.TIFF: allure.attachment_type.TIFF,
AllureAttachmentType.MP4: allure.attachment_type.MP4,
AllureAttachmentType.OGG: allure.attachment_type.OGG,
AllureAttachmentType.WEBM: allure.attachment_type.WEBM,
AllureAttachmentType.PDF: allure.attachment_type.PDF, }
_attachment_type = attachment_type_mapping.get(getattr(AllureAttachmentType, _name.upper(), None), None)
allure.attach.file(source=source, name=name,
attachment_type=_attachment_type,
extension=_name)
class AllureReportBeautiful:
"""
美化allure测试报告
"""
@staticmethod
def set_windows_title(new_title):
"""
设置打开的 Allure 报告的浏览器窗口标题文案
@param new_title: 需要更改的标题文案 原文案为Allure Report
@return:
"""
report_title_filepath = os.path.join(ALLURE_REPORT_DIR, "index.html")
# 定义为只读模型,并定义名称为: f
with open(report_title_filepath, 'r+', encoding="utf-8") as f:
# 读取当前文件的所有内容
all_the_lines = f.readlines()
f.seek(0)
f.truncate()
# 循环遍历每一行的内容,将 "Allure Report" 全部替换为 → new_title(新文案)
for line in all_the_lines:
f.write(line.replace("Allure Report", new_title))
# 关闭文件
f.close()
@staticmethod
def set_report_name(new_name):
"""
修改Allure报告Overview的标题文案
@param new_name: 需要更改的标题文案 原文案为ALLURE REPORT
@return:
"""
title_filepath = os.path.join(ALLURE_REPORT_DIR, "widgets", "summary.json")
# 读取summary.json中的json数据并改写reportName
with open(title_filepath, 'rb') as f:
# 加载json文件中的内容给params
params = json.load(f)
# 修改内容
params['reportName'] = new_name
# 将修改后的内容保存在dict中
new_params = params
# 往summary.json中覆盖写入新的json数据
with open(title_filepath, 'w', encoding="utf-8") as f:
json.dump(new_params, f, ensure_ascii=False, indent=4)
@staticmethod
def set_report_env_on_results():
"""
在allure-results报告的根目录下生成一个写入了环境信息的文件environment.properties(注意不能放置中文否则会出现乱码)
@return:
"""
# 需要写入的环境信息
allure_env = {
'OperatingEnvironment': ENV.name,
'BaseUrl': EntryPoint.URL(),
'PythonVersion': platform.python_version(),
'Platform': platform.platform(),
'PytestVersion': pytest.__version__,
}
allure_env_file = os.path.join(TEMP_DIR, 'environment.properties')
with open(allure_env_file, 'w', encoding='utf-8') as f:
for _k, _v in allure_env.items():
f.write(f'{_k}={_v}\n')
@staticmethod
def set_report_executer_on_results():
"""
在allure-results报告的根目录下生成一个写入了执行人的文件executor.json
@return:
"""
# 需要写入的环境信息
allure_executor = {
"name": "汪杰",
"type": "jenkins",
"url": "http://helloqa.com",
"buildOrder": 3,
"buildName": "allure-report_deploy#1",
"buildUrl": "http://helloqa.com#1",
"reportUrl": "http://helloqa.com#1/AllureReport",
"reportName": "汪杰 Allure Report"
}
allure_env_file = os.path.join(TEMP_DIR, 'executor.json')
with open(allure_env_file, 'w', encoding='utf-8') as f:
f.write(str(json.dumps(allure_executor, ensure_ascii=False, indent=4)))