This commit is contained in:
chenyongzhiaaron 2023-07-21 10:39:23 +08:00
commit 88d9fe7beb
9 changed files with 210 additions and 148 deletions

View File

@ -2,7 +2,7 @@
<project version="4">
<component name="dataSourceStorageLocal" created-in="PY-231.9161.41">
<data-source name="@localhost" uuid="49b6f686-3676-4df5-9645-cd7a2fe91d80">
<database-info product="MySQL" version="8.0.26" jdbc-version="4.2" driver-name="MySQL Connector/J" driver-version="mysql-connector-java-8.0.25 (Revision: 08be9e9b4cba6aa115f9b27b215887af40b159e0)" dbms="MYSQL" exact-version="8.0.26" exact-driver-version="8.0">
<database-info product="MySQL" version="8.0.32" jdbc-version="4.2" driver-name="MySQL Connector/J" driver-version="mysql-connector-java-8.0.25 (Revision: 08be9e9b4cba6aa115f9b27b215887af40b159e0)" dbms="MYSQL" exact-version="8.0.32" exact-driver-version="8.0">
<extra-name-characters>#@</extra-name-characters>
<identifier-quote-string>`</identifier-quote-string>
</database-info>

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<dataSource name="@localhost">
<database-model serializer="dbm" dbms="MYSQL" family-id="MYSQL" format-version="4.48">
<root id="1">
<DefaultCasing>lower/lower</DefaultCasing>
<DefaultEngine>InnoDB</DefaultEngine>
<DefaultTmpEngine>InnoDB</DefaultTmpEngine>
<ServerVersion>8.0.32</ServerVersion>
</root>
<schema id="2" parent="1" name="flask">
<CollationName>utf8mb4_0900_ai_ci</CollationName>
</schema>
<schema id="3" parent="1" name="information_schema">
<CollationName>utf8mb3_general_ci</CollationName>
</schema>
<schema id="4" parent="1" name="mysql">
<CollationName>utf8mb4_0900_ai_ci</CollationName>
</schema>
<schema id="5" parent="1" name="performance_schema">
<CollationName>utf8mb4_0900_ai_ci</CollationName>
</schema>
<schema id="6" parent="1" name="sys">
<CollationName>utf8mb4_0900_ai_ci</CollationName>
</schema>
</database-model>
</dataSource>

15
OutPut/log/2023-07-20.log Normal file
View File

@ -0,0 +1,15 @@
2023-07-20 23:39:11 | ERROR | 查询异常 sql: select username,password as pwd from user where username ='luoshunwen003';
2023-07-20 23:39:11 | ERROR | 数据库操作异常: 'MysqlClient' object has no attribute 'cursor'
2023-07-20 23:39:11 | ERROR | | called execute_sql | error: 快看,异常了,别唧唧哇哇,快排查!!: 'MysqlClient' object has no attribute 'cursor'
2023-07-20 23:39:11 | ERROR | 被提取对象非字典、非字符串、非列表不执行jsonpath提取被提取对象: None
2023-07-20 23:40:14 | ERROR | 查询异常 sql: select username,password as pwd from lea.user where username ='luoshunwen003';
2023-07-20 23:40:14 | ERROR | 数据库操作异常: 'MysqlClient' object has no attribute 'cursor'
2023-07-20 23:40:14 | ERROR | | called execute_sql | error: 快看,异常了,别唧唧哇哇,快排查!!: 'MysqlClient' object has no attribute 'cursor'
2023-07-20 23:40:14 | ERROR | 被提取对象非字典、非字符串、非列表不执行jsonpath提取被提取对象: None
2023-07-20 23:40:23 | ERROR | 查询异常 sql: select username,password as pwd from lea.user where username ='luoshunwen003';
2023-07-20 23:40:23 | ERROR | 数据库操作异常: 'MysqlClient' object has no attribute 'cursor'
2023-07-20 23:40:23 | ERROR | | called execute_sql | error: 快看,异常了,别唧唧哇哇,快排查!!: 'MysqlClient' object has no attribute 'cursor'
2023-07-20 23:41:11 | ERROR | 查询异常 sql: select username,password as pwd from lea.user where username ='luoshunwen003';
2023-07-20 23:41:11 | ERROR | 数据库操作异常: 'MysqlClient' object has no attribute 'cursor'
2023-07-20 23:42:16 | ERROR | 查询异常 sql: select username,password as pwd from lea.user where username ='luoshunwen003';
2023-07-20 23:42:16 | ERROR | 数据库操作异常: 'MysqlClient' object has no attribute 'cursor'

37
OutPut/log/2023-07-21.log Normal file
View File

@ -0,0 +1,37 @@
2023-07-21 00:15:54 | ERROR | 执行 sql 失败:{'select': {'select_one': "select username,password as pwd from user where username ='luoshunwen003';"}},异常信息:'MysqlClient' object has no attribute 'do_mysql'
2023-07-21 00:15:55 | ERROR | key:<re.Match object; span=(102, 116), match='{{tvSequence}}'>,在关联参数表中查询不到,请检查关联参数字段提取及填写是否正常
2023-07-21 00:15:55 | ERROR | 异常用例: **safe_4_劳务基础配置_绑定TV**
'FAIL' unexpectedly found in ('FAIL', [{'检查项': '$.code', '期望值': 200, '实际值': 'AG_100003', '断言方法': 'eq:实际值与期望值相等'}, {'检查项': '$.msg', '期望值': '添加成功', '实际值': '您的登陆状态已过期,请重新登陆。', '断言方法': 'eq:实际值与期望值相等'}]) : FAIL 存在结果元组中
2023-07-21 00:15:56 | ERROR | key:<re.Match object; span=(171, 184), match='{{BSP_TOKEN}}'>,在关联参数表中查询不到,请检查关联参数字段提取及填写是否正常
2023-07-21 00:15:56 | ERROR | 提取失败:提取表达式:$.data.projectId没有提取到对应的值
2023-07-21 00:15:56 | ERROR | 异常用例: **safe_5_劳务基础配置_查询配置**
'FAIL' unexpectedly found in ('FAIL', [{'检查项': '$.data.projectId', '期望值': '103654', '实际值': [], '断言方法': 'contained_by:实际值被包含在期望值中'}]) : FAIL 存在结果元组中
2023-07-21 00:16:39 | ERROR | 提取失败:提取表达式:$.data.projectId没有提取到对应的值
2023-07-21 00:16:39 | ERROR | 异常用例: **safe_5_劳务基础配置_查询配置**
'FAIL' unexpectedly found in ('FAIL', [{'检查项': '$.data.projectId', '期望值': '103654', '实际值': [], '断言方法': 'contained_by:实际值被包含在期望值中'}]) : FAIL 存在结果元组中
2023-07-21 00:18:28 | ERROR | 提取失败:提取表达式:$.data.projectId没有提取到对应的值
2023-07-21 00:18:28 | ERROR | 异常用例: **safe_5_劳务基础配置_查询配置**
'FAIL' unexpectedly found in ('FAIL', [{'检查项': '$.data.projectId', '期望值': '103654', '实际值': [], '断言方法': 'contained_by:实际值被包含在期望值中'}]) : FAIL 存在结果元组中
2023-07-21 00:19:03 | ERROR | 提取失败:提取表达式:$.data.projectId没有提取到对应的值
2023-07-21 00:19:03 | ERROR | 异常用例: **safe_5_劳务基础配置_查询配置**
'FAIL' unexpectedly found in ('FAIL', [{'检查项': '$.data.projectId', '期望值': '103654', '实际值': [], '断言方法': 'contained_by:实际值被包含在期望值中'}]) : FAIL 存在结果元组中
2023-07-21 00:20:12 | ERROR | 提取失败:提取表达式:$.data.projectId没有提取到对应的值
2023-07-21 00:20:12 | ERROR | 异常用例: **safe_5_劳务基础配置_查询配置**
'FAIL' unexpectedly found in ('FAIL', [{'检查项': '$.data.projectId', '期望值': '103654', '实际值': [], '断言方法': 'contained_by:实际值被包含在期望值中'}]) : FAIL 存在结果元组中
2023-07-21 00:41:18 | ERROR | 提取失败:提取表达式:$.data.projectId没有提取到对应的值
2023-07-21 00:41:18 | ERROR | 异常用例: **safe_5_劳务基础配置_查询配置**
'FAIL' unexpectedly found in ('FAIL', [{'检查项': '$.data.projectId', '期望值': '103654', '实际值': [], '断言方法': 'contained_by:实际值被包含在期望值中'}]) : FAIL 存在结果元组中
2023-07-21 00:42:07 | ERROR | 提取失败:提取表达式:$.data.projectId没有提取到对应的值
2023-07-21 00:42:07 | ERROR | 异常用例: **safe_5_劳务基础配置_查询配置**
'FAIL' unexpectedly found in ('FAIL', [{'检查项': '$.data.projectId', '期望值': '103654', '实际值': [], '断言方法': 'contained_by:实际值被包含在期望值中'}]) : FAIL 存在结果元组中
2023-07-21 00:44:24 | ERROR | 提取失败:提取表达式:$.data.projectId没有提取到对应的值
2023-07-21 00:44:24 | ERROR | 异常用例: **safe_5_劳务基础配置_查询配置**
'FAIL' unexpectedly found in ('FAIL', [{'检查项': '$.data.projectId', '期望值': '103654', '实际值': [], '断言方法': 'contained_by:实际值被包含在期望值中'}]) : FAIL 存在结果元组中
2023-07-21 00:49:16 | ERROR | 提取失败:提取表达式:$.data.projectId没有提取到对应的值
2023-07-21 00:49:16 | ERROR | 异常用例: **safe_5_劳务基础配置_查询配置**
'FAIL' unexpectedly found in ('FAIL', [{'检查项': '$.data.projectId', '期望值': '103654', '实际值': [], '断言方法': 'contained_by:实际值被包含在期望值中'}]) : FAIL 存在结果元组中
2023-07-21 00:52:03 | ERROR | 提取失败:提取表达式:$.data.projectId没有提取到对应的值
2023-07-21 00:52:03 | ERROR | 异常用例: **safe_5_劳务基础配置_查询配置**
'FAIL' unexpectedly found in ('FAIL', [{'检查项': '$.data.projectId', '期望值': '103654', '实际值': [], '断言方法': 'contained_by:实际值被包含在期望值中'}]) : FAIL 存在结果元组中

Binary file not shown.

Binary file not shown.

View File

@ -14,12 +14,14 @@ from common.utils.decorators import singleton
from common.utils.load_and_execute_script import LoadScript
from common.validation.extractor import Extractor
from common.validation.validator import Validator
from common.database.mysql_client import MysqlClient
@singleton
class Action(Extractor, LoadScript, Validator):
def __init__(self, initialize_data=None, bif_functions=None):
class Action(Extractor, LoadScript, Validator, MysqlClient):
def __init__(self, initialize_data=None, bif_functions=None, db_config=None):
super().__init__()
MysqlClient.__init__(self, db_config)
self.encrypt = EncryptData()
self.__variables = {}
self.set_environments(initialize_data)

View File

@ -18,146 +18,130 @@ from common.database import logger
from common.utils.decorators import singleton
@singleton
# @singleton
class MysqlClient:
def __init__(self, db_config):
"""
初始化连接配置
Args:
db_config: 数据库连接配置字典
"""
if not db_config:
return
def __init__(self, db_config):
"""
初始化连接配置
Args:
db_config: 数据库连接配置字典
"""
if not db_config:
return
self.result = {}
try:
self.db_base = db_config if isinstance(db_config, dict) else json.loads(db_config)
print(self.db_base)
self.pool = PooledDB(creator=pymysql, maxconnections=10, **self.db_base)
self.conn = self.pool.connection()
self.cursor = self.conn.cursor(DictCursor)
except Exception as e:
logger.error(f"数据库链接失败: {e}")
raise
# @logger.log_decorator()
def execute_sql(self, sql):
"""
执行 SQL 语句
try:
self.db_base = db_config if isinstance(db_config, dict) else json.loads(db_config)
self.pool = PooledDB(creator=pymysql, maxconnections=10, **self.db_base)
except Exception as e:
logger.error(f"数据库链接失败: {e}")
raise
Args:
sql: SQL 语句字典
{
"delete": {
"sql_name": "DELETE FROM table_name WHERE condition"
},
"update": {
"sql_name": "UPDATE table_name SET column1=value1 WHERE condition"
},
"insert": {
"sql_name": "INSERT INTO table_name (column1, column2) VALUES (value1, value2)"
},
"select": {
"sql_name": "SELECT * FROM table_name WHERE condition"
}
}
@logger.log_decorator()
def execute_sql(self, sql):
"""
执行 SQL 语句
Returns:
执行结果字典
{
"sql_name": [result1, result2, ...]
}
"""
if not sql:
return
try:
for method, sql_data in sql.items():
execute_method = getattr(self, f"_execute_{method}", None)
if not execute_method:
logger.error("sql字典集编写格式不符合规范")
raise ValueError("Invalid SQL method")
logger.info(f"执行 sql 语句集: {sql_data}")
execute_method(sql_data)
self.cursor.close()
self.conn.close()
return self.result
except Exception as e:
logger.error(f"数据库操作异常: {e}")
raise
def _execute_write(self, sql_data):
"""
执行通用的写入操作INSERTUPDATEDELETE
"""
for sql_name, sql_ in sql_data.items():
try:
self.cursor.execute(str(sql_))
except Exception as err:
logger.error(f"执行 SQL 异常: {sql_}")
raise err
self.cursor.connection.commit()
def _execute_select(self, sql_data):
"""
执行 SELECT 语句
Args:
sql: SQL 语句字典
{
"delete": {
"sql_name": "DELETE FROM table_name WHERE condition"
},
"update": {
"sql_name": "UPDATE table_name SET column1=value1 WHERE condition"
},
"insert": {
"sql_name": "INSERT INTO table_name (column1, column2) VALUES (value1, value2)"
},
"select": {
"sql_name": "SELECT * FROM table_name WHERE condition"
}
}
Args:
cursor: 数据库游标
sql_data: SQL 语句数据字典
{
"sql_name": "SELECT * FROM table_name WHERE condition"
}
result: 字典结果
Returns:
执行结果字典
{
"sql_name": [result1, result2, ...]
}
"""
if not sql:
return
try:
conn = self.pool.connection()
cur = conn.cursor(DictCursor)
result = {}
for method, sql_data in sql.items():
execute_method = getattr(self, f"_execute_{method}", None)
if not execute_method:
logger.error("sql字典集编写格式不符合规范")
raise ValueError("Invalid SQL method")
execute_method(cur, sql_data, result)
cur.close()
conn.close()
return result
except Exception as e:
logger.error(f"数据库操作异常: {e}")
raise
def _execute_delete(self, cursor, sql_data, result):
"""
执行 DELETE 语句
"""
for sql_name, sql_ in sql_data.items():
try:
cursor.execute(str(sql_))
except Exception as err:
logger.error(f"执行 SQL 异常: {sql_}")
raise err
cursor.connection.commit()
def _execute_update(self, cursor, sql_data, result):
"""
执行 UPDATE 语句
"""
self.execute_delete(cursor, sql_data, result)
def _execute_insert(self, cursor, sql_data, result):
"""
执行 INSERT 语句
"""
self.execute_delete(cursor, sql_data, result)
def _execute_select(self, cursor, sql_data, result):
"""
执行 SELECT 语句
Args:
cursor: 数据库游标
sql_data: SQL 语句数据字典
{
"sql_name": "SELECT * FROM table_name WHERE condition"
}
result: 字典结果
Raises:
Exception: 执行异常
"""
for sql_name, sql_ in sql_data.items():
try:
cursor.execute(sql_)
result[sql_name] = cursor.fetchall()
except Exception as err:
logger.error(f"查询异常 sql: {sql_}")
raise err
Raises:
Exception: 执行异常
"""
for sql_name, sql_ in sql_data.items():
try:
self.cursor.execute(sql_)
self.result[sql_name] = self.cursor.fetchall()
except Exception as err:
logger.error(f"查询异常 sql: {sql_}")
raise err
if __name__ == '__main__':
sql_2 = {
"select":
{
"select_sale": "select count(1) total, (case when t1.status = 1 then '待整改' when t1.status = 2 then '待复查' when t1.status = 3 then '整改完成' else '未知类型' end) orderStatus from ibs_ai_iot.ai_rectification_main t1 left join ibs_ai_iot.work_order t3 on t1.id = t3.rectification_id where t1.project_id = 103672 and t1.delete_flag = 0 and t3.is_delete = 0 group by t1.status order by orderStatus desc;",
"select_sale_1": "select count(1) total, (case when t1.status = 1 then '待整改' when t1.status = 2 then '待复查' when t1.status = 3 then '整改完成' else '未知类型' end) orderStatus from ibs_ai_iot.ai_rectification_main t1 left join ibs_ai_iot.work_order t3 on t1.id = t3.rectification_id where t1.project_id = 103672 and t1.delete_flag = 0 and t3.is_delete = 0 group by t1.status order by orderStatus desc;"
}
sql_2 = {
"select":
{
"select_one": "select username,password as pwd from lea.user where username ='luoshunwen003';"
}
}
database_2 = {
"host": "localhost",
"port": 3306,
"database": "lea",
"user": "root",
"password": "admin"
}
res = MysqlClient(database_2).execute_sql(sql_2)
print("数据执行结果", res)
from common.data_extraction.data_extractor import DataExtractor
from common.environments import Environments
}
database_2 = {
"host": "10.10.10.10",
"port": 3306,
"database": "base",
"user": "root",
"password": "roottttttttttttttttttttest"
}
res = MysqlClient(database_2).execute_sql(sql_2)
print("数据执行结果", res)
from common.data_extraction.data_extractor import DataExtractor
from common.environments import Environments
t = DataExtractor()
t.substitute_data(res, jp_dict={"total": "$.select_sale[0].total", "total_1": "$..total"})
print(Environments.get_environments())
# t = DataExtractor()
# t.substitute_data(res, jp_dict={"total": "$.select_sale[0].total", "total_1": "$..total"})
# print(Environments.get_environments())

View File

@ -16,7 +16,6 @@ excel = DoExcel(test_file)
init_data, test_case = excel.get_excel_init_and_cases()
databases = init_data.get('databases') # 获取数据库配置信息
mysql = MysqlClient(databases) # 初始化 mysql 链接
logger = MyLogger()
initialize_data = eval(init_data.get("initialize_data"))
@ -26,7 +25,7 @@ host = init_data.get('host', "") + init_data.get("path", "")
@ddt
class TestProjectApi(unittest.TestCase):
maxDiff = None
action = Action(initialize_data, bif_functions)
action = Action(initialize_data, bif_functions, databases)
@classmethod
def setUpClass(cls) -> None:
@ -39,13 +38,15 @@ class TestProjectApi(unittest.TestCase):
def test_api(self, item):
sheet, iid, condition, st, name, desc, h_crypto, r_crypto, method, expected = self.__base_info(item)
if self.__is_run(condition):
self.skipTest("这个测试用例听说泡面比较好吃,所以放弃执行了")
self.skipTest("这个测试用例听说泡面比较好吃,所以放弃执行了")
regex, keys, deps, jp_dict, ex_request_data = self.__extractor_info(item)
setup_script, teardown_script = self.script(item)
self.__pause_execution(st)
# 首执行 sql
self.__exc_sql(item, method)
self.__exc_sql(item)
if method.upper() == 'SQL':
self.skipTest("这条测试用例被 SQL 吃了,所以放弃执行了!!")
# 执行动态代码
item = self.action.execute_dynamic_code(item, setup_script)
@ -59,7 +60,7 @@ class TestProjectApi(unittest.TestCase):
# 分析请求参数信息
headers, request_data = self.action.analysis_request(request_data, h_crypto, headers, r_crypto, ex_request_data)
result_tuple = None
result_tp = None
result = "PASS"
# 执行请求操作
@ -172,20 +173,17 @@ class TestProjectApi(unittest.TestCase):
logger.error("暂时时间必须是数字")
raise e
def __exc_sql(self, item, method):
def __exc_sql(self, item):
sql, sql_params_dict = self.__sql_info(item)
sql = self.action.replace_dependent_parameter(sql)
if sql:
try:
execute_sql_results = mysql.do_mysql(sql)
execute_sql_results = self.action.execute_sql(sql)
if execute_sql_results and sql_params_dict:
self.action.extract_request_data(execute_sql_results, jp_dict=sql_params_dict)
if method == "SQL" and mysql:
return None
self.action.substitute_data(execute_sql_results, jp_dict=sql_params_dict)
except Exception as e:
logger.error(f'执行 sql 失败:{sql},异常信息:{e}')
raise e
return sql
if __name__ == '__main__':