diff --git a/case_utils/assert_handle.py b/case_utils/assert_handle.py index d39a6d5..ad98487 100644 --- a/case_utils/assert_handle.py +++ b/case_utils/assert_handle.py @@ -8,7 +8,7 @@ from case_utils.allure_handle import allure_step from requests import Response -from common_utils.data_handle import json_extractor, re_extract +from case_utils.data_handle import json_extractor, re_extract from loguru import logger from case_utils.request_data_handle import response_type from common_utils.mysql_handle import MysqlServer @@ -30,8 +30,7 @@ def assert_response(response: Response, expected: dict) -> None: f"-------------Start:响应断言--------------------\n") if expected is None: logger.info("当前用例无响应断言!") - allure_step(step_title='判断是否存在响应断言', - content='当前用例无响应断言!') + allure_step(step_title='判断是否存在响应断言---->当前用例无响应断言!') return logger.debug(f"响应断言预期结果:{expected}, {type(expected)}") index = 0 @@ -49,8 +48,7 @@ def assert_response(response: Response, expected: dict) -> None: actual = re_extract(response.text, _k) index += 1 logger.info(f'第{index}个响应断言 -|- 预期结果: {_k}: {_v}, {type(_v)} {k} 实际结果: {actual}, {type(actual)}') - allure_step(step_title=f'第{index}个响应断言数据', - content=f'预期结果: {_k}: {_v}, {type(_v)} {k} 实际结果: {actual}, {type(actual)}') + allure_step(step_title=f'第{index}个响应断言数据---->预期结果: {_k}: {_v}, {type(_v)} {k} 实际结果: {actual}, {type(actual)}') try: if k == "eq": # 预期结果 = 实际结果 assert _v == actual @@ -73,8 +71,7 @@ def assert_response(response: Response, expected: dict) -> None: content='目前仅支持如下关键字:eq, in, gt, lt, not') except AssertionError: logger.error(f"第{index}个响应断言失败 -|- 预期结果: {_k}: {_v}, {type(_v)} {k} 实际结果: {actual}, {type(actual)}") - allure_step(step_title=f'第{index}个响应断言失败', - content=f'预期结果: {_k}: {_v}, {type(_v)} {k} 实际结果: {actual}, {type(actual)}') + allure_step(step_title=f'第{index}个响应断言失败---->预期结果: {_k}: {_v}, {type(_v)} {k} 实际结果: {actual}, {type(actual)}') logger.info('\n-------------End:响应断言--------------------\n' \ "=====================================================") raise AssertionError( @@ -100,14 +97,12 @@ def assert_sql(db_info, expected: dict): f"-------------Start:数据库断言--------------------") if expected is None: logger.info("当前用例无数据库断言!") - allure_step(step_title='判断是否存在数据库断言', - content='当前用例无数据库断言') + allure_step(step_title='判断是否存在数据库断言---->当前用例无数据库断言') return if not db_info: logger.error("当前环境无数据库配置,跳过数据库断言!") - allure_step(step_title='判断是否存在数据库配置', - content='当前环境无数据库配置,跳过数据库断言!}') - logger.info('\n-------------End:数据库断言--------------------\n' \ + allure_step(step_title='判断是否存在数据库配置---->当前环境无数据库配置,跳过数据库断言!') + logger.info('\n-------------End:数据库断言--------------------\n' "=====================================================") return for k, v in expected.items(): @@ -118,13 +113,13 @@ def assert_sql(db_info, expected: dict): # 查询数据库,获取查询结果 sql_result = MysqlServer(**db_info).query_one(_v) logger.info(f'数据库响应断言 -|- SQL:{_v} || 查询结果:{sql_result}') - allure_step(step_title=f'数据库断言', - content=f'SQL:{_v} || 查询结果:{sql_result}') + allure_step(step_title=f'数据库断言---->SQL:{_v} ', + content=f'查询结果:{sql_result}') except Exception as e: logger.error(f'数据库服务报错:{e}') allure_step(step_title=f'数据库服务报错', content=f'{e} ') - logger.info('\n-------------End:数据库断言--------------------\n' \ + logger.info('\n-------------End:数据库断言--------------------\n' "=====================================================") raise AssertionError(f"数据库服务报错:{e}") @@ -133,19 +128,16 @@ def assert_sql(db_info, expected: dict): if _k == "len": assert _v == len(sql_result) logger.info(f"预期结果: {_v} == 实际结果: {len(sql_result)}, 断言成功!") - allure_step(step_title=f'---->数据库断言结果', - content=f'预期结果: {_v} == 实际结果: {len(sql_result)}, 断言成功!') + allure_step(step_title=f'数据库断言结果---->预期结果: {_v} == 实际结果: {len(sql_result)}, 断言成功!') # 如果时$.开头,则从数据库查询结果中提取相应的值作为实际结果 elif _k.startswith("$."): actual = json_extractor(sql_result, _k) assert _v == actual logger.info(f"预期结果: {_v} == 实际结果: {actual}, 断言成功!") - allure_step(step_title=f'---->数据库断言结果', - content=f'预期结果: {_v} == 实际结果: {actual}, 断言成功!') + allure_step(step_title=f'数据库断言结果---->预期结果: {_v} == 实际结果: {actual}, 断言成功!') except AssertionError: logger.error(f"数据库断言失败 -|- 预期结果:{_v} {k} 实际结果: {sql_result})") - allure_step(step_title=f'数据库断言失败', - content=f'预期结果:{_v} {k} 实际结果: {sql_result}') + allure_step(step_title=f'数据库断言失败---->预期结果:{_v} {k} 实际结果: {sql_result}') logger.info('\n-------------End:数据库断言--------------------\n' \ "=====================================================") raise AssertionError(f"数据库断言失败 -|-预期结果: {_v} {k} 实际结果: {sql_result}") diff --git a/common_utils/data_handle.py b/case_utils/data_handle.py similarity index 52% rename from common_utils/data_handle.py rename to case_utils/data_handle.py index 8df11b4..4f724e3 100644 --- a/common_utils/data_handle.py +++ b/case_utils/data_handle.py @@ -5,114 +5,42 @@ # @File : data_handle.py # @Software: PyCharm # @Desc: 数据处理 -from jsonpath import jsonpath + import re -from faker import Faker from string import Template +from jsonpath import jsonpath from loguru import logger +from faker import Faker faker = Faker() -def data_replace(content, source): +def data_handle(obj, source): """ - 用例数据替换的方法 - :param content: 原始的字符串内容 - :param source: 需要替换字符串的来源 - return content: 替换表达式后的字符串 + 递归处理字典、列表中的字符串,将${}占位符替换成source中的值 """ - try: - if content is None: - return None - logger.debug("\n======================================================\n" \ - "-------------Start:数据替换--------------------\n" - f"替换源: {source}\n" \ - f"初始字符串: {content}\n" \ - "=====================================================") - print(f"-----Start-----数据替换: 初始字符串为:{content}") - if len(content) != 0: - # safe_substitute() 方法会保留没有被替换的占位符,不会抛出 KeyError 异常。 - # 所以,如果 content 中不存在占位符,使用 safe_substitute() 方法进行替换后,得到的结果和原始字符串是一样的。 - content = Template(str(content)).safe_substitute(source) - for func in re.findall('\\${(.*?)}', content): - content = content.replace('${%s}' % func, exec_func(func)) - try: - content = content.replace('${%s}' % func, exec_func(func)) - except Exception as e: - logger.error(f"\n======================================================\n" \ - "-------------End:数据替换--------------------\n" - f"替换数据时出现了异常:{e}" \ - "=====================================================") - print(f"-----END-----替换数据时出现了异常:{e}") - return e - logger.debug("\n======================================================\n" \ - "-------------End:数据替换--------------------\n" - f"新字符串:{content}\n" \ - "=====================================================") - print(f"-----End-----数据替换完成: 新字符串为:{type(content)} || {content}\n") - return content - except Exception as e: - logger.error(f"进行数据替换时报错:{e}") - print(f"进行数据替换时报错:{e}") + obj = eval_data_process(obj) + if isinstance(obj, str): + # 寻找${}, 在source中找到对应的关键字进行替换,如obj=${user_id}, 去寻找source中对应键user_id的值(假设user_id=1),使得obj=1 + obj = Template(obj).safe_substitute(source) + # 寻找${python表达式}, 将Python表达式eval得出其具体值 + for func in re.findall('\\${(.*?)}', obj): + obj = obj.replace('${%s}' % func, eval_data_process(func)) + obj = eval_data_process(obj) + return obj + return eval_data_process(obj) + elif isinstance(obj, list): + for index, item in enumerate(obj): + obj[index] = data_handle(item, source) + return obj + elif isinstance(obj, dict): + for key, value in obj.items(): + obj[key] = data_handle(value, source) + return obj -def json_extractor(obj: dict, expr: str = '.'): - """ - :param obj :json/dict类型数据 - :param expr: 表达式, . 提取字典所有内容, $.test_api_case 提取一级字典case, $.test_api_case.data 提取case字典下的data - :return result: 提取的结果,未提取到返回 None - """ - try: - result = jsonpath(obj, expr)[0] - logger.debug("\n======================================================\n" \ - "-------------Start:json_extractor--------------------\n" - f"提取表达式为: {expr} 提取值为 {result}\n" \ - "=====================================================") - print("提取响应内容成功,提取表达式为: {} 提取值为 {}".format(expr, result)) - except Exception as e: - logger.debug("\n======================================================\n" \ - "-------------End:json_extractor--------------------\n" - f"提取表达式为: {expr} 提取数据为 {obj}\n, 错误信息为:{e}\n" \ - "=====================================================") - print(f'未提取到内容,请检查表达式是否错误!提取表达式为:{expr} 提取数据为 {obj}, 错误信息为:{e}') - result = None - return result - - -def re_extract(obj: str, expr: str = '.'): - """ - :param obj : 字符串数据 - :param expr: 正则表达式 - :return result: 提取的结果,未提取到返回 None - """ - try: - result = re.findall(expr, obj)[0] - logger.debug("\n======================================================\n" \ - "-------------Start:re_extract--------------------\n" - f"提取表达式为: {expr} 提取值为: {result}\n" \ - "=====================================================") - print("提取响应内容成功,提取表达式为: {} 提取值为: {}".format(expr, result)) - except Exception as e: - logger.debug(f"\n======================================================\n" \ - "-------------End:re_extract--------------------\n" - f"提取表达式为: {expr} 提取数据为:{obj}\n, 错误信息为:{e}\n" \ - "=====================================================") - print(f'未提取到内容,请检查表达式是否错误!提取表达式为:{expr} 提取数据为 {obj}, 错误信息为:{e}') - result = None - return result - - -def exec_func(func) -> str: - """ - :params func 字符的形式调用函数 - : return 返回的转换成函数执行的结果,已字符串格式返回 - """ - result = eval(func) - logger.debug("\n======================================================\n" \ - "-------------exec_func--------------------\n" - f"函数: {func} 执行结果: {result}\n" \ - "=====================================================") - return str(result) + else: + return obj # 将"[1,2,3]" 或者"{'k':'v'}" -> [1,2,3], {'k':'v'} @@ -145,3 +73,55 @@ def eval_data_process(data): for key, value in data.items(): data[key] = eval_data_process(eval_data(value)) return data + + +def json_extractor(obj: dict, expr: str = '.'): + """ + :param obj :json/dict类型数据 + :param expr: 表达式, . 提取字典所有内容, $.test_api_case 提取一级字典case, $.test_api_case.data 提取case字典下的data + :return result: 提取的结果,未提取到返回 None + """ + try: + result = jsonpath(obj, expr)[0] + logger.debug("\n======================================================\n" \ + "-------------Start:json_extractor--------------------\n" + f"提取表达式为: {expr} \n" + f"提取值为: {result}\n" + "=====================================================") + print("提取响应内容成功,提取表达式为: {} 提取值为 {}".format(expr, result)) + except Exception as e: + logger.debug("\n======================================================\n" \ + "-------------End:json_extractor--------------------\n" + f"提取表达式为: {expr}\n" + f"提取数据为: {obj}\n" + f"错误信息为:{e}\n" + "=====================================================") + print(f'未提取到内容,请检查表达式是否错误!提取表达式为:{expr} 提取数据为 {obj}, 错误信息为:{e}') + result = None + return result + + +def re_extract(obj: str, expr: str = '.'): + """ + :param obj : 字符串数据 + :param expr: 正则表达式 + :return result: 提取的结果,未提取到返回 None + """ + try: + result = re.findall(expr, obj)[0] + logger.debug("\n======================================================\n" \ + "-------------Start:re_extract--------------------\n" + f"提取表达式为: {expr}\n" \ + f"提取值为: {result}\n" \ + "=====================================================") + print("提取响应内容成功,提取表达式为: {} 提取值为: {}".format(expr, result)) + except Exception as e: + logger.debug(f"\n======================================================\n" \ + "-------------End:re_extract--------------------\n" + f"提取表达式为: {expr}\n" \ + f"提取数据为: {obj}\n" \ + f"错误信息为:{e}\n" \ + "=====================================================") + print(f'未提取到内容,请检查表达式是否错误!提取表达式为:{expr} 提取数据为 {obj}, 错误信息为:{e}') + result = None + return result diff --git a/case_utils/request_data_handle.py b/case_utils/request_data_handle.py index 0abcfb8..1223aa7 100644 --- a/case_utils/request_data_handle.py +++ b/case_utils/request_data_handle.py @@ -8,11 +8,11 @@ import json import os.path from common_utils.files_handle import get_file_field -from common_utils.data_handle import eval_data_process, data_replace +from case_utils.data_handle import eval_data_process, data_handle from config.global_vars import GLOBAL_VARS from requests import Response from loguru import logger -from common_utils.data_handle import json_extractor, re_extract +from case_utils.data_handle import json_extractor, re_extract from case_utils.allure_handle import allure_step from common_utils.base_request import BaseRequest from config.path_config import FILES_DIR @@ -28,17 +28,17 @@ class RequestPreDataHandle: def __init__(self, request_data): logger.debug(f"\n======================================================\n" \ "-------------Start:处理用例数据前--------------------\n" - f"用例标题: {type(request_data.get('title', None))} || {request_data.get('title', None)}\n" \ - f"请求路径: {type(request_data.get('url', None))} || {request_data.get('url', None)}\n" \ - f"请求方式: {type(request_data.get('method', None))} || {request_data.get('method', None)}\n" \ - f"请求头: {type(request_data.get('headers', None))} || {request_data.get('headers', None)}\n" \ + f"用例标题(title): {type(request_data.get('title', None))} || {request_data.get('title', None)}\n" \ + f"请求路径(url): {type(request_data.get('url', None))} || {request_data.get('url', None)}\n" \ + f"请求方式(method): {type(request_data.get('method', None))} || {request_data.get('method', None)}\n" \ + f"请求头(headers): {type(request_data.get('headers', None))} || {request_data.get('headers', None)}\n" \ f"请求cookies: {type(request_data.get('cookies', None))} || {request_data.get('cookies', None)}\n" \ - f"请求类型: {type(request_data.get('request_type', None))} || {request_data.get('request_type', None)}\n" \ - f"请求内容: {type(request_data.get('payload', None))} || {request_data.get('payload', None)}\n" \ - f"请求文件: {type(request_data.get('files', None))} || {request_data.get('files', None)}\n" \ - f"后置提取参数: {type(request_data.get('extract', None))} || {request_data.get('extract', None)}\n" \ - f"响应断言: {type(request_data.get('assert_response', None))} || {request_data.get('assert_response', None)}\n" \ - f"数据库断言: {type(request_data.get('assert_sql', None))} || {request_data.get('assert_sql', None)}\n" \ + f"请求类型(request_type): {type(request_data.get('request_type', None))} || {request_data.get('request_type', None)}\n" \ + f"请求参数(payload): {type(request_data.get('payload', None))} || {request_data.get('payload', None)}\n" \ + f"请求文件(files): {type(request_data.get('files', None))} || {request_data.get('files', None)}\n" \ + f"后置提取参数(extract): {type(request_data.get('extract', None))} || {request_data.get('extract', None)}\n" \ + f"响应断言(assert_response): {type(request_data.get('assert_response', None))} || {request_data.get('assert_response', None)}\n" \ + f"数据库断言(assert_sql): {type(request_data.get('assert_sql', None))} || {request_data.get('assert_sql', None)}\n" \ "=====================================================") self.request_data = request_data @@ -56,17 +56,17 @@ class RequestPreDataHandle: self.assert_handle() logger.debug(f"\n======================================================\n" \ "-------------End:处理用例数据后--------------------\n" - f"用例标题: {type(self.request_data.get('title', None))} || {self.request_data.get('title', None)}\n" \ - f"请求路径: {type(self.request_data.get('url', None))} || {self.request_data.get('url', None)}\n" \ - f"请求方式: {type(self.request_data.get('method', None))} || {self.request_data.get('method', None)}\n" \ - f"请求头: {type(self.request_data.get('headers', None))} || {self.request_data.get('headers', None)}\n" \ + f"用例标题(title): {type(self.request_data.get('title', None))} || {self.request_data.get('title', None)}\n" \ + f"请求路径(url): {type(self.request_data.get('url', None))} || {self.request_data.get('url', None)}\n" \ + f"请求方式(method): {type(self.request_data.get('method', None))} || {self.request_data.get('method', None)}\n" \ + f"请求头(headers): {type(self.request_data.get('headers', None))} || {self.request_data.get('headers', None)}\n" \ f"请求cookies: {type(self.request_data.get('cookies', None))} || {self.request_data.get('cookies', None)}\n" \ - f"请求类型: {type(self.request_data.get('request_type', None))} || {self.request_data.get('request_type', None)}\n" \ - f"请求内容: {type(self.request_data.get('payload', None))} || {self.request_data.get('payload', None)}\n" \ - f"请求文件: {type(self.request_data.get('files', None))} || {self.request_data.get('files', None)}\n" \ - f"后置提取参数: {type(self.request_data.get('extract', None))} || {self.request_data.get('extract', None)}\n" \ - f"响应断言: {type(self.request_data.get('assert_response', None))} || {self.request_data.get('assert_response', None)}\n" \ - f"数据库断言: {type(self.request_data.get('assert_sql', None))} || {self.request_data.get('assert_sql', None)}\n" \ + f"请求类型(request_type): {type(self.request_data.get('request_type', None))} || {self.request_data.get('request_type', None)}\n" \ + f"请求参数(payload): {type(self.request_data.get('payload', None))} || {self.request_data.get('payload', None)}\n" \ + f"请求文件(files): {type(self.request_data.get('files', None))} || {self.request_data.get('files', None)}\n" \ + f"后置提取参数(extract): {type(self.request_data.get('extract', None))} || {self.request_data.get('extract', None)}\n" \ + f"响应断言(assert_response): {type(self.request_data.get('assert_response', None))} || {self.request_data.get('assert_response', None)}\n" \ + f"数据库断言(assert_sql): {type(self.request_data.get('assert_sql', None))} || {self.request_data.get('assert_sql', None)}\n" \ "=====================================================") return self.request_data @@ -76,7 +76,7 @@ class RequestPreDataHandle: 用例数据中获取到的url(一般是不带host的,个别特殊的带有host,则不进行处理) """ # 检测url中是否存在需要替换的参数,如果存在则进行替换 - data_replace(content=self.request_data.get("url", None), source=GLOBAL_VARS) + data_handle(obj=self.request_data.get("url", None), source=GLOBAL_VARS) # 进行url处理,最终得到full_url host = GLOBAL_VARS.get("host", "") url = self.request_data.get("url", "") @@ -115,7 +115,7 @@ class RequestPreDataHandle: # 从用例数据中获取cookies, 处理cookies if cookies: # 通过全局变量替换cookies,得到的是一个str类型 - cookies = data_replace(content=cookies, source=GLOBAL_VARS) + cookies = data_handle(obj=cookies, source=GLOBAL_VARS) if isinstance(cookies, str): # 如果是字符串类型,就转成字典 self.request_data["cookies"] = json.loads(cookies) @@ -133,8 +133,7 @@ class RequestPreDataHandle: try: # 从用例数据中获取header, 处理header if headers: - self.request_data["headers"] = eval_data_process( - data_replace(content=headers, source=GLOBAL_VARS)) + self.request_data["headers"] = data_handle(obj=headers, source=GLOBAL_VARS) # 如果请求头中有cookies,需要进行单独处理 if self.request_data["headers"].get("cookies", None): cookies = self.request_data["headers"]["cookies"] @@ -152,8 +151,7 @@ class RequestPreDataHandle: payload = self.request_data.get("payload", None) try: if payload: - self.request_data["payload"] = eval_data_process( - data_replace(content=payload, source=GLOBAL_VARS)) + self.request_data["payload"] = data_handle(obj=payload, source=GLOBAL_VARS) except Exception as e: logger.error(f"处理{payload}报错了:{e}") print(f"处理{payload}报错了:{e}") @@ -207,8 +205,7 @@ class RequestPreDataHandle: assert_response = self.request_data.get("assert_response", None) try: if assert_response: - self.request_data["assert_response"] = eval_data_process( - data_replace(content=assert_response, source=GLOBAL_VARS)) + self.request_data["assert_response"] = data_handle(obj=assert_response, source=GLOBAL_VARS) # 由于数据库断言里面的变量需要请求响应后进行提取,因此目前不进行处理 except Exception as e: logger.error(f"处理{assert_response}报错了:{e}") @@ -231,30 +228,43 @@ class RequestHandle: response = BaseRequest.send_request(self.case_data) # 处理数据库断言 - 从全局变量中获取最新值,替换数据库断言中的参数 if self.case_data.get('assert_sql', None): - self.case_data["assert_sql"] = eval_data_process( - data_replace(content=self.case_data["assert_sql"], source=GLOBAL_VARS)) - logger.info(f"\n======================================================\n" \ - "-------------请求数据--------------------\n" - f"用例标题: {type(self.case_data.get('title', None))} || {self.case_data.get('title', None)}\n" \ - f"请求路径: {type(self.case_data.get('url', None))} || {self.case_data.get('url', None)}\n" \ - f"请求方式: {type(self.case_data.get('method', None))} || {self.case_data.get('method', None)}\n" \ - f"请求头: {type(self.case_data.get('headers', None))} || {self.case_data.get('headers', None)}\n" \ - f"请求cookies: {type(self.case_data.get('cookies', None))} || {self.case_data.get('cookies', None)}\n" \ - f"请求类型: {type(self.case_data.get('request_type', None))} || {self.case_data.get('request_type', None)}\n" \ - f"请求内容: {type(self.case_data.get('payload', None))} || {self.case_data.get('payload', None)}\n" \ - f"请求文件: {type(self.case_data.get('files', None))} || {self.case_data.get('files', None)}\n" \ - f"请求响应数据: {response.text}\n" \ - f"请求响应码: {response.status_code}\n" \ - f"响应耗时: {round(response.elapsed.total_seconds(), 2)} s || {round(response.elapsed.total_seconds() * 1000, 2)} ms\n" \ - "=====================================================") - allure_step(step_title=f"请求地址:{self.case_data['url']}") - allure_step(step_title=f"请求方式:{self.case_data['method']}") - allure_step(step_title="请求头", content=self.case_data['headers']) + self.case_data["assert_sql"] = data_handle(obj=self.case_data["assert_sql"], source=GLOBAL_VARS) + logger.info(f"\n======================================================\n" + "-------------执行请求获取响应数据--------------------\n" + f"用例标题(title): {type(self.case_data.get('title', None))} || {self.case_data.get('title', None)}\n" + f"请求路径(url): {type(self.case_data.get('url', None))} || {self.case_data.get('url', None)}\n" + f"请求方式(method): {type(self.case_data.get('method', None))} || {self.case_data.get('method', None)}\n" + f"请求头(headers): {type(self.case_data.get('headers', None))} || {self.case_data.get('headers', None)}\n" + f"请求cookies: {type(self.case_data.get('cookies', None))} || {self.case_data.get('cookies', None)}\n" + f"请求类型(request_type): {type(self.case_data.get('request_type', None))} || {self.case_data.get('request_type', None)}\n" + f"请求参数(payload): {type(self.case_data.get('payload', None))} || {self.case_data.get('payload', None)}\n") + allure_step(step_title=f"请求地址(url):{self.case_data['url']}") + allure_step(step_title=f"请求方式(method):{self.case_data['method']}") + allure_step(step_title="请求头(headers)", content=self.case_data['headers']) allure_step(step_title="请求Cookies", content=str(self.case_data['cookies'])) - allure_step(step_title="请求参数", content=self.case_data['payload']) - allure_step(step_title="请求文件", content=self.case_data['files']) - allure_step(step_title="请求响应数据", content=response.text) - allure_step(step_title=f"请求响应码:{response.status_code}") + allure_step(step_title="请求参数(payload)", content=self.case_data['payload']) + # 处理请求里面的files,使得日志以及allure中写入的是文件,而不是文件二进制内容 + if self.case_data.get('files', None): + files = self.case_data["files"] + if isinstance(files, list): + for file in files: + _file = os.path.join(FILES_DIR, file[1][0]) + logger.info( + f"\n请求文件(files): {type(_file)} || {_file}\n") + allure_step(step_title="请求文件(files)", source=_file) + elif isinstance(files, dict): + dict_values = list(files.values())[0] + _file = os.path.join(FILES_DIR, dict_values[0]) + logger.info( + f"\n请求文件(files): {type(_file)} || {_file}\n") + allure_step(step_title="请求文件(files)", source=_file) + logger.info( + f"\n请求响应数据(response): {response.text}\n" + f"请求响应码(code): {response.status_code}\n" + f"响应耗时: {round(response.elapsed.total_seconds(), 2)} s || {round(response.elapsed.total_seconds() * 1000, 2)} ms\n" + "=====================================================") + allure_step(step_title="请求响应数据(response)", content=response.text) + allure_step(step_title=f"请求响应码(code):{response.status_code}") allure_step( step_title=f"响应耗时:{round(response.elapsed.total_seconds(), 2)} s || {round(response.elapsed.total_seconds() * 1000, 2)} ms") return response @@ -308,7 +318,3 @@ def response_type(response: Response) -> str: return "json" except: return "str" - -if __name__ == '__main__': - test = RequestPreDataHandle(request_data={"files": {"file": ["导入TOC订单.xls", "toc.xls"]}}) - test.files_handle() \ No newline at end of file diff --git a/case_utils/send_result_handle.py b/case_utils/send_result_handle.py index a8191a8..1e7fa56 100644 --- a/case_utils/send_result_handle.py +++ b/case_utils/send_result_handle.py @@ -12,7 +12,7 @@ from config.settings import SEND_RESULT_TYPE, email, ding_talk, wechat, email_su ding_talk_content, wechat_content from common_utils.dingding_handle import DingTalkBot from common_utils.wechat_handle import WechatBot -from common_utils.data_handle import data_replace +from case_utils.data_handle import data_handle from case_utils.get_results_handle import get_test_results_from_pytest_html_report, \ get_test_results_from_from_allure_report @@ -125,7 +125,7 @@ def send_result(report_path, report_type="allure", attachment_path=None): if SEND_RESULT_TYPE in notification_mappings: notification = notification_mappings[SEND_RESULT_TYPE] # 获取消息内容并替换 - notification['sender_args']['content'] = data_replace(notification['sender_args']['content'], + notification['sender_args']['content'] = data_handle(notification['sender_args']['content'], source=results) # 获取消息发送函数 sender = notification['sender'] @@ -138,7 +138,7 @@ def send_result(report_path, report_type="allure", attachment_path=None): # 遍历所有消息发送方式 for notification in notification_mappings.values(): # 获取消息内容并替换 - notification['sender_args']['content'] = data_replace(notification['sender_args']['content'], + notification['sender_args']['content'] = data_handle(notification['sender_args']['content'], source=results) # 获取消息发送函数 sender = notification['sender'] diff --git a/config/allure_config/gitlinklogo.jpg b/config/allure_config/gitlinklogo.jpg new file mode 100644 index 0000000..824a4a9 Binary files /dev/null and b/config/allure_config/gitlinklogo.jpg differ diff --git a/config/allure_config/微信图片_20230615174806.jpg b/config/allure_config/微信图片_20230615174806.jpg new file mode 100644 index 0000000..c9fbb9d Binary files /dev/null and b/config/allure_config/微信图片_20230615174806.jpg differ diff --git a/config/allure_config/微信图片_20230615174812.png b/config/allure_config/微信图片_20230615174812.png new file mode 100644 index 0000000..378b197 Binary files /dev/null and b/config/allure_config/微信图片_20230615174812.png differ diff --git a/config/allure_config/微信图片_20230615174817.jpg b/config/allure_config/微信图片_20230615174817.jpg new file mode 100644 index 0000000..c27e2a4 Binary files /dev/null and b/config/allure_config/微信图片_20230615174817.jpg differ diff --git a/data/login_demo.yaml b/data/gitlink/login_demo.yaml similarity index 99% rename from data/login_demo.yaml rename to data/gitlink/login_demo.yaml index 66c7a08..31de927 100644 --- a/data/login_demo.yaml +++ b/data/gitlink/login_demo.yaml @@ -7,7 +7,7 @@ case_common: case_login_demo_01: feature: 登录 title: 用户名密码正确,登录成功(不校验数据库) - run: True + run: False url: /api/accounts/login.json method: POST headers: {"Content-Type": "application/json; charset=utf-8;"} diff --git a/data/test_gitlink_demo.xlsx b/data/gitlink/test_gitlink_demo.xlsx similarity index 63% rename from data/test_gitlink_demo.xlsx rename to data/gitlink/test_gitlink_demo.xlsx index 2c98df4..f4e6ffe 100644 Binary files a/data/test_gitlink_demo.xlsx and b/data/gitlink/test_gitlink_demo.xlsx differ diff --git a/data/test_new_project_demo.yaml b/data/gitlink/test_new_project_demo.yaml similarity index 99% rename from data/test_new_project_demo.yaml rename to data/gitlink/test_new_project_demo.yaml index 8266515..2922ab8 100644 --- a/data/test_new_project_demo.yaml +++ b/data/gitlink/test_new_project_demo.yaml @@ -34,7 +34,7 @@ case_new_project_demo_01: case_new_project_demo_02: feature: 新建项目 title: 正确输入各项必填参数,新建项目成功(不校验数据库,单独传cookies) - run: True + run: False url: /api/projects.json method: POST headers: diff --git a/data/test_upload_files.yaml b/data/gitlink/test_upload_files.yaml similarity index 94% rename from data/test_upload_files.yaml rename to data/gitlink/test_upload_files.yaml index da38a3d..12d3727 100644 --- a/data/test_upload_files.yaml +++ b/data/gitlink/test_upload_files.yaml @@ -1,6 +1,6 @@ # 公共参数 case_common: - allure_epic: GitLink接口(手动编写用例) + allure_epic: GitLink接口(自动生成用例) allure_feature: 上传文件模块 allure_story: 上传文件 diff --git a/files/TOC出库订单导入模板(2).xlsx b/files/TOC出库订单导入模板(2).xlsx new file mode 100644 index 0000000..08afc6e Binary files /dev/null and b/files/TOC出库订单导入模板(2).xlsx differ diff --git a/files/toc.xls b/files/toc.xls new file mode 100644 index 0000000..5ecca49 Binary files /dev/null and b/files/toc.xls differ diff --git a/files/导入TOC订单.xls b/files/导入TOC订单.xls new file mode 100644 index 0000000..e6ee943 Binary files /dev/null and b/files/导入TOC订单.xls differ diff --git a/pytest.ini b/pytest.ini index b2b6fd0..526825f 100644 --- a/pytest.ini +++ b/pytest.ini @@ -1,6 +1,6 @@ [pytest] # cmd params -addopts = -s --cache-clear --capture=sys --self-contained-html --reruns=0 --reruns-delay=5 +addopts = -s --cache-clear --capture=sys --self-contained-html --reruns=0 --reruns-delay=0 disable_test_id_escaping_and_forfeit_all_rights_to_community_support = True markers = test_login_demo: login diff --git a/test_case/test_manual_case/test_login_demo.py b/test_case/test_manual_case/test_login_demo.py index 0a0235c..14fd199 100644 --- a/test_case/test_manual_case/test_login_demo.py +++ b/test_case/test_manual_case/test_login_demo.py @@ -21,7 +21,7 @@ from config.settings import db_info from config.global_vars import GLOBAL_VARS # 读取用例数据 -yaml_data = YamlHandle(filename=os.path.join(DATA_DIR, "login_demo.yaml")).read_yaml +yaml_data = YamlHandle(filename=os.path.join(DATA_DIR, "gitlink", "login_demo.yaml")).read_yaml case_common = yaml_data["case_common"] cases = [] for k, v in yaml_data.items():