修复由上传文件引起的断言失败的bug

增加动态读取扩展脚本函数的功能
修复由多继承导致的找不到父类方法的问题。
This commit is contained in:
aaronchenyongzhi 2023-07-13 20:37:11 +08:00
parent 9133a0509d
commit 3fcfa58ed0
22 changed files with 942 additions and 528 deletions

View File

@ -5,7 +5,7 @@
<sourceFolder url="file://$MODULE_DIR$" isTestSource="false" />
<excludeFolder url="file://$MODULE_DIR$/venv" />
</content>
<orderEntry type="jdk" jdkName="Python 3.9" jdkType="Python SDK" />
<orderEntry type="jdk" jdkName="Pipenv (apitest)" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
<component name="PackageRequirementsSettings">

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="dataSourceStorageLocal" created-in="PY-231.9161.41">
<component name="dataSourceStorageLocal" created-in="PY-231.9011.38">
<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">
<extra-name-characters>#@</extra-name-characters>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.9" project-jdk-type="Python SDK" />
<component name="ProjectRootManager" version="2" project-jdk-name="Pipenv (apitest)" project-jdk-type="Python SDK" />
<component name="PyCharmProfessionalAdvertiser">
<option name="shown" value="true" />
</component>

View File

@ -197,3 +197,101 @@ exceptions must derive from BaseException
2023-07-13 18:04:14 | ERROR | 提取失败提取表达式data[0].tvSequence没有提取到对应的值
2023-07-13 18:04:14 | ERROR | 异常用例: 安全纯净大屏_5_劳务基础配置_查询配置
'FAIL' unexpectedly found in ('FAIL', [{'检查项': 'data[0].tvSequence', '期望值': '{{tvSequence}}', '实际值': [], '断言方法': 'contained_by:实际值被包含在期望值中'}]) : FAIL 存在结果元组中
2023-07-13 18:52:43 | ERROR | | called load_built_in_comparators | error: 快看,异常了,别唧唧哇哇,块排查: load_built_in_comparators() missing 1 required positional argument: 'self'
2023-07-13 18:53:56 | ERROR | | called load_built_in_comparators | error: 快看,异常了,别唧唧哇哇,块排查: load_built_in_comparators() missing 1 required positional argument: 'self'
2023-07-13 18:54:30 | ERROR | | called load_built_in_comparators | error: 快看,异常了,别唧唧哇哇,块排查: load_built_in_comparators() missing 1 required positional argument: 'self'
2023-07-13 18:54:56 | ERROR | | called load_built_in_comparators | error: 快看,异常了,别唧唧哇哇,块排查: load_built_in_comparators() missing 1 required positional argument: 'self'
2023-07-13 18:55:00 | ERROR | 异常用例: 安全纯净大屏_4_劳务基础配置_绑定TV
'FAIL' unexpectedly found in ('FAIL', [{'检查项': 'code', '期望值': 200, '实际值': 'AG_100003', '断言方法': 'eq:实际值与期望值相等'}, {'检查项': 'msg', '期望值': '添加成功', '实际值': '您的登陆状态已过期,请重新登陆。', '断言方法': 'eq:实际值与期望值相等'}]) : FAIL 存在结果元组中
2023-07-13 18:55:01 | ERROR | key:<re.Match object; span=(365, 379), match='{{tvSequence}}'>,在关联参数表中查询不到,请检查关联参数字段提取及填写是否正常
2023-07-13 18:55:01 | ERROR | 被提取对象非字典、非字符串、非列表不执行jsonpath提取被提取对象: None
2023-07-13 18:55:01 | ERROR | 提取失败提取表达式data[0].tvSequence没有提取到对应的值
2023-07-13 18:55:01 | ERROR | 异常用例: 安全纯净大屏_5_劳务基础配置_查询配置
'FAIL' unexpectedly found in ('FAIL', [{'检查项': 'data[0].tvSequence', '期望值': '{{tvSequence}}', '实际值': [], '断言方法': 'contained_by:实际值被包含在期望值中'}]) : FAIL 存在结果元组中
2023-07-13 19:10:18 | ERROR | | called load_built_in_comparators | error: 快看,异常了,别唧唧哇哇,块排查: load_built_in_comparators() missing 1 required positional argument: 'self'
2023-07-13 19:10:21 | ERROR | 异常用例: 安全纯净大屏_4_劳务基础配置_绑定TV
'FAIL' unexpectedly found in ('FAIL', [{'检查项': 'code', '期望值': 200, '实际值': 'AG_100003', '断言方法': 'eq:实际值与期望值相等'}, {'检查项': 'msg', '期望值': '添加成功', '实际值': '您的登陆状态已过期,请重新登陆。', '断言方法': 'eq:实际值与期望值相等'}]) : FAIL 存在结果元组中
2023-07-13 19:10:22 | ERROR | key:<re.Match object; span=(365, 379), match='{{tvSequence}}'>,在关联参数表中查询不到,请检查关联参数字段提取及填写是否正常
2023-07-13 19:10:22 | ERROR | 被提取对象非字典、非字符串、非列表不执行jsonpath提取被提取对象: None
2023-07-13 19:10:22 | ERROR | 提取失败提取表达式data[0].tvSequence没有提取到对应的值
2023-07-13 19:10:22 | ERROR | 异常用例: 安全纯净大屏_5_劳务基础配置_查询配置
'FAIL' unexpectedly found in ('FAIL', [{'检查项': 'data[0].tvSequence', '期望值': '{{tvSequence}}', '实际值': [], '断言方法': 'contained_by:实际值被包含在期望值中'}]) : FAIL 存在结果元组中
2023-07-13 19:15:37 | ERROR | | called load_built_in_functions | error: 快看,异常了,别唧唧哇哇,块排查: vars() argument must have __dict__ attribute
2023-07-13 19:15:37 | ERROR | | called set_bif_fun | error: 快看,异常了,别唧唧哇哇,块排查: 'NoneType' object has no attribute 'items'
2023-07-13 19:16:12 | ERROR | | called load_built_in_functions | error: 快看,异常了,别唧唧哇哇,块排查: vars() argument must have __dict__ attribute
2023-07-13 19:16:12 | ERROR | | called set_bif_fun | error: 快看,异常了,别唧唧哇哇,块排查: 'NoneType' object has no attribute 'items'
2023-07-13 19:30:55 | ERROR | | called load_built_in_comparators | error: 快看,异常了,别唧唧哇哇,块排查: load_built_in_comparators() missing 1 required positional argument: 'self'
2023-07-13 19:30:57 | ERROR | 异常用例: 安全纯净大屏_2_登录_非BIP用户登录
HTTPSConnectionPool(host='bimdc.bzlrobot.com', port=443): Max retries exceeded with url: /bsp/test/user/ugs/auth/loginByNotBip (Caused by ProxyError('Unable to connect to proxy', SSLError(SSLEOFError(8, 'EOF occurred in violation of protocol (_ssl.c:1123)'))))
2023-07-13 19:30:58 | ERROR | 异常用例: 安全纯净大屏_4_劳务基础配置_绑定TV
HTTPSConnectionPool(host='bimdc.bzlrobot.com', port=443): Max retries exceeded with url: /bsp/test/user/ugs/ibs/api/ibs-lms-base/tvConfig/addTvSequence?t=1689247858607 (Caused by ProxyError('Unable to connect to proxy', SSLError(SSLEOFError(8, 'EOF occurred in violation of protocol (_ssl.c:1123)'))))
2023-07-13 19:30:59 | ERROR | key:<re.Match object; span=(365, 379), match='{{tvSequence}}'>,在关联参数表中查询不到,请检查关联参数字段提取及填写是否正常
2023-07-13 19:30:59 | ERROR | 被提取对象非字典、非字符串、非列表不执行jsonpath提取被提取对象: None
2023-07-13 19:30:59 | ERROR | 异常用例: 安全纯净大屏_5_劳务基础配置_查询配置
HTTPSConnectionPool(host='bimdc.bzlrobot.com', port=443): Max retries exceeded with url: /bsp/test/user/ugs/ibs/api/ibs-lms-base/tvConfig/getTvInfo?t=1689247859760&projectId=104966 (Caused by ProxyError('Unable to connect to proxy', SSLError(SSLEOFError(8, 'EOF occurred in violation of protocol (_ssl.c:1123)'))))
2023-07-13 19:31:09 | ERROR | | called load_built_in_comparators | error: 快看,异常了,别唧唧哇哇,块排查: load_built_in_comparators() missing 1 required positional argument: 'self'
2023-07-13 19:31:12 | ERROR | 异常用例: 安全纯净大屏_4_劳务基础配置_绑定TV
'FAIL' unexpectedly found in ('FAIL', [{'检查项': 'code', '期望值': 200, '实际值': 'AG_100003', '断言方法': 'eq:实际值与期望值相等'}, {'检查项': 'msg', '期望值': '添加成功', '实际值': '您的登陆状态已过期,请重新登陆。', '断言方法': 'eq:实际值与期望值相等'}]) : FAIL 存在结果元组中
2023-07-13 19:31:13 | ERROR | key:<re.Match object; span=(365, 379), match='{{tvSequence}}'>,在关联参数表中查询不到,请检查关联参数字段提取及填写是否正常
2023-07-13 19:31:13 | ERROR | 被提取对象非字典、非字符串、非列表不执行jsonpath提取被提取对象: None
2023-07-13 19:31:13 | ERROR | 提取失败提取表达式data[0].tvSequence没有提取到对应的值
2023-07-13 19:31:13 | ERROR | 异常用例: 安全纯净大屏_5_劳务基础配置_查询配置
'FAIL' unexpectedly found in ('FAIL', [{'检查项': 'data[0].tvSequence', '期望值': '{{tvSequence}}', '实际值': [], '断言方法': 'contained_by:实际值被包含在期望值中'}]) : FAIL 存在结果元组中
2023-07-13 19:39:56 | ERROR | | called load_built_in_comparators | error: 快看,异常了,别唧唧哇哇,块排查: load_built_in_comparators() missing 1 required positional argument: 'self'
2023-07-13 19:39:59 | ERROR | 异常用例: safe_4_劳务基础配置_绑定TV
'FAIL' unexpectedly found in ('FAIL', [{'检查项': 'code', '期望值': 200, '实际值': 200, '断言方法': 'eq:实际值与期望值相等'}, {'检查项': 'msg', '期望值': '添加成功', '实际值': '添加成功', '断言方法': 'eq:实际值与期望值相等'}]) : FAIL 存在结果元组中
2023-07-13 19:40:00 | ERROR | key:<re.Match object; span=(411, 425), match='{{tvSequence}}'>,在关联参数表中查询不到,请检查关联参数字段提取及填写是否正常
2023-07-13 19:40:00 | ERROR | 被提取对象非字典、非字符串、非列表不执行jsonpath提取被提取对象: None
2023-07-13 19:40:00 | ERROR | 提取失败提取表达式data[0].tvSequence没有提取到对应的值
2023-07-13 19:40:00 | ERROR | 异常用例: safe_5_劳务基础配置_查询配置
'FAIL' unexpectedly found in ('FAIL', [{'检查项': 'data[0].tvSequence', '期望值': '{{tvSequence}}', '实际值': [], '断言方法': 'contained_by:实际值被包含在期望值中'}]) : FAIL 存在结果元组中
2023-07-13 19:43:55 | ERROR | | called load_built_in_comparators | error: 快看,异常了,别唧唧哇哇,块排查: load_built_in_comparators() missing 1 required positional argument: 'self'
2023-07-13 19:43:58 | ERROR | 异常用例: safe_4_劳务基础配置_绑定TV
'FAIL' unexpectedly found in ('FAIL', [{'检查项': 'code', '期望值': 200, '实际值': 200, '断言方法': 'eq:实际值与期望值相等'}, {'检查项': 'msg', '期望值': '添加成功', '实际值': '添加成功', '断言方法': 'eq:实际值与期望值相等'}]) : FAIL 存在结果元组中
2023-07-13 19:43:59 | ERROR | 被提取对象非字典、非字符串、非列表不执行jsonpath提取被提取对象: None
2023-07-13 19:43:59 | ERROR | 异常用例: safe_5_劳务基础配置_查询配置
'FAIL' unexpectedly found in ('FAIL', [{'检查项': 'data.projectId', '期望值': '104966', '实际值': '104966', '断言方法': 'contained_by:实际值被包含在期望值中'}]) : FAIL 存在结果元组中
2023-07-13 19:44:23 | ERROR | | called load_built_in_comparators | error: 快看,异常了,别唧唧哇哇,块排查: load_built_in_comparators() missing 1 required positional argument: 'self'
2023-07-13 19:47:38 | ERROR | 被提取对象非字典、非字符串、非列表不执行jsonpath提取被提取对象: None
2023-07-13 19:50:03 | ERROR | 异常用例: safe_2_登录_非BIP用户登录
HTTPSConnectionPool(host='bimdc.bzlrobot.com', port=443): Max retries exceeded with url: /bsp/test/user/ugs/auth/loginByNotBip (Caused by ProxyError('Unable to connect to proxy', SSLError(SSLEOFError(8, 'EOF occurred in violation of protocol (_ssl.c:1123)'))))
2023-07-13 19:50:04 | ERROR | 异常用例: safe_4_劳务基础配置_绑定TV
HTTPSConnectionPool(host='bimdc.bzlrobot.com', port=443): Max retries exceeded with url: /bsp/test/user/ugs/ibs/api/ibs-lms-base/tvConfig/addTvSequence?t=1689249004213 (Caused by ProxyError('Unable to connect to proxy', SSLError(SSLEOFError(8, 'EOF occurred in violation of protocol (_ssl.c:1123)'))))
2023-07-13 19:50:05 | ERROR | 被提取对象非字典、非字符串、非列表不执行jsonpath提取被提取对象: None
2023-07-13 19:50:05 | ERROR | 异常用例: safe_5_劳务基础配置_查询配置
HTTPSConnectionPool(host='bimdc.bzlrobot.com', port=443): Max retries exceeded with url: /bsp/test/user/ugs/ibs/api/ibs-lms-base/tvConfig/getTvInfo?t=1689249005341&projectId=104966 (Caused by ProxyError('Unable to connect to proxy', SSLError(SSLEOFError(8, 'EOF occurred in violation of protocol (_ssl.c:1123)'))))
2023-07-13 19:50:17 | ERROR | 异常用例: safe_4_劳务基础配置_绑定TV
'Action' object has no attribute 'built_in_comparators'
2023-07-13 19:50:18 | ERROR | 被提取对象非字典、非字符串、非列表不执行jsonpath提取被提取对象: None
2023-07-13 19:50:18 | ERROR | 异常用例: safe_5_劳务基础配置_查询配置
'Action' object has no attribute 'built_in_comparators'
2023-07-13 19:51:09 | ERROR | 异常用例: safe_4_劳务基础配置_绑定TV
'Action' object has no attribute 'built_in_comparators'
2023-07-13 19:51:10 | ERROR | 被提取对象非字典、非字符串、非列表不执行jsonpath提取被提取对象: None
2023-07-13 19:51:10 | ERROR | 异常用例: safe_5_劳务基础配置_查询配置
'Action' object has no attribute 'built_in_comparators'
2023-07-13 20:10:34 | ERROR | 异常用例: safe_2_登录_非BIP用户登录
HTTPSConnectionPool(host='bimdc.bzlrobot.com', port=443): Max retries exceeded with url: /bsp/test/user/ugs/auth/loginByNotBip (Caused by ProxyError('Unable to connect to proxy', SSLError(SSLEOFError(8, 'EOF occurred in violation of protocol (_ssl.c:1123)'))))
2023-07-13 20:10:35 | ERROR | 异常用例: safe_4_劳务基础配置_绑定TV
HTTPSConnectionPool(host='bimdc.bzlrobot.com', port=443): Max retries exceeded with url: /bsp/test/user/ugs/ibs/api/ibs-lms-base/tvConfig/addTvSequence?t=1689250235406 (Caused by ProxyError('Unable to connect to proxy', SSLError(SSLEOFError(8, 'EOF occurred in violation of protocol (_ssl.c:1123)'))))
2023-07-13 20:10:36 | ERROR | 被提取对象非字典、非字符串、非列表不执行jsonpath提取被提取对象: None
2023-07-13 20:10:36 | ERROR | 异常用例: safe_5_劳务基础配置_查询配置
HTTPSConnectionPool(host='bimdc.bzlrobot.com', port=443): Max retries exceeded with url: /bsp/test/user/ugs/ibs/api/ibs-lms-base/tvConfig/getTvInfo?t=1689250236535&projectId=104966 (Caused by ProxyError('Unable to connect to proxy', SSLError(SSLEOFError(8, 'EOF occurred in violation of protocol (_ssl.c:1123)'))))
2023-07-13 20:10:52 | ERROR | 异常用例: safe_4_劳务基础配置_绑定TV
'Action' object has no attribute 'built_in_comparators'
2023-07-13 20:10:53 | ERROR | 被提取对象非字典、非字符串、非列表不执行jsonpath提取被提取对象: None
2023-07-13 20:10:53 | ERROR | 异常用例: safe_5_劳务基础配置_查询配置
'Action' object has no attribute 'built_in_comparators'
2023-07-13 20:11:51 | ERROR | 被提取对象非字典、非字符串、非列表不执行jsonpath提取被提取对象: None
2023-07-13 20:20:37 | ERROR | 被提取对象非字典、非字符串、非列表不执行jsonpath提取被提取对象: None
2023-07-13 20:23:07 | ERROR | 被提取对象非字典、非字符串、非列表不执行jsonpath提取被提取对象: None
2023-07-13 20:24:02 | ERROR | 被提取对象非字典、非字符串、非列表不执行jsonpath提取被提取对象: None
2023-07-13 20:27:02 | ERROR | 被提取对象非字典、非字符串、非列表不执行jsonpath提取被提取对象: None
2023-07-13 20:27:55 | ERROR | 被提取对象非字典、非字符串、非列表不执行jsonpath提取被提取对象: None
2023-07-13 20:31:15 | ERROR | 被提取对象非字典、非字符串、非列表不执行jsonpath提取被提取对象: None
2023-07-13 20:33:24 | ERROR | 被提取对象非字典、非字符串、非列表不执行jsonpath提取被提取对象: None

14
Pipfile
View File

@ -4,6 +4,20 @@ verify_ssl = true
name = "pypi"
[packages]
jsonpath-ng = "*"
ddt = "*"
jsonpath = "*"
requests = "*"
urllib3 = "*"
pymysql = "*"
rsa = "*"
loguru = "*"
faker = "*"
natsort = "*"
pydes = "*"
pyyaml = "*"
dbutils = "*"
openpyxl = "*"
[dev-packages]

314
Pipfile.lock generated
View File

@ -1,7 +1,7 @@
{
"_meta": {
"hash": {
"sha256": "a36a5392bb1e8bbc06bfaa0761e52593cf2d83b486696bf54667ba8da616c839"
"sha256": "201d66441c82a043f090c7acba0b6b6712d26a2660cd266c65b11888dfc9f399"
},
"pipfile-spec": 6,
"requires": {
@ -15,6 +15,316 @@
}
]
},
"default": {},
"default": {
"certifi": {
"hashes": [
"sha256:0f0d56dc5a6ad56fd4ba36484d6cc34451e1c6548c61daad8c320169f91eddc7",
"sha256:c6c2e98f5c7869efca1f8916fed228dd91539f9f1b444c314c06eef02980c716"
],
"markers": "python_version >= '3.6'",
"version": "==2023.5.7"
},
"charset-normalizer": {
"hashes": [
"sha256:04e57ab9fbf9607b77f7d057974694b4f6b142da9ed4a199859d9d4d5c63fe96",
"sha256:09393e1b2a9461950b1c9a45d5fd251dc7c6f228acab64da1c9c0165d9c7765c",
"sha256:0b87549028f680ca955556e3bd57013ab47474c3124dc069faa0b6545b6c9710",
"sha256:1000fba1057b92a65daec275aec30586c3de2401ccdcd41f8a5c1e2c87078706",
"sha256:1249cbbf3d3b04902ff081ffbb33ce3377fa6e4c7356f759f3cd076cc138d020",
"sha256:1920d4ff15ce893210c1f0c0e9d19bfbecb7983c76b33f046c13a8ffbd570252",
"sha256:193cbc708ea3aca45e7221ae58f0fd63f933753a9bfb498a3b474878f12caaad",
"sha256:1a100c6d595a7f316f1b6f01d20815d916e75ff98c27a01ae817439ea7726329",
"sha256:1f30b48dd7fa1474554b0b0f3fdfdd4c13b5c737a3c6284d3cdc424ec0ffff3a",
"sha256:203f0c8871d5a7987be20c72442488a0b8cfd0f43b7973771640fc593f56321f",
"sha256:246de67b99b6851627d945db38147d1b209a899311b1305dd84916f2b88526c6",
"sha256:2dee8e57f052ef5353cf608e0b4c871aee320dd1b87d351c28764fc0ca55f9f4",
"sha256:2efb1bd13885392adfda4614c33d3b68dee4921fd0ac1d3988f8cbb7d589e72a",
"sha256:2f4ac36d8e2b4cc1aa71df3dd84ff8efbe3bfb97ac41242fbcfc053c67434f46",
"sha256:3170c9399da12c9dc66366e9d14da8bf7147e1e9d9ea566067bbce7bb74bd9c2",
"sha256:3b1613dd5aee995ec6d4c69f00378bbd07614702a315a2cf6c1d21461fe17c23",
"sha256:3bb3d25a8e6c0aedd251753a79ae98a093c7e7b471faa3aa9a93a81431987ace",
"sha256:3bb7fda7260735efe66d5107fb7e6af6a7c04c7fce9b2514e04b7a74b06bf5dd",
"sha256:41b25eaa7d15909cf3ac4c96088c1f266a9a93ec44f87f1d13d4a0e86c81b982",
"sha256:45de3f87179c1823e6d9e32156fb14c1927fcc9aba21433f088fdfb555b77c10",
"sha256:46fb8c61d794b78ec7134a715a3e564aafc8f6b5e338417cb19fe9f57a5a9bf2",
"sha256:48021783bdf96e3d6de03a6e39a1171ed5bd7e8bb93fc84cc649d11490f87cea",
"sha256:4957669ef390f0e6719db3613ab3a7631e68424604a7b448f079bee145da6e09",
"sha256:5e86d77b090dbddbe78867a0275cb4df08ea195e660f1f7f13435a4649e954e5",
"sha256:6339d047dab2780cc6220f46306628e04d9750f02f983ddb37439ca47ced7149",
"sha256:681eb3d7e02e3c3655d1b16059fbfb605ac464c834a0c629048a30fad2b27489",
"sha256:6c409c0deba34f147f77efaa67b8e4bb83d2f11c8806405f76397ae5b8c0d1c9",
"sha256:7095f6fbfaa55defb6b733cfeb14efaae7a29f0b59d8cf213be4e7ca0b857b80",
"sha256:70c610f6cbe4b9fce272c407dd9d07e33e6bf7b4aa1b7ffb6f6ded8e634e3592",
"sha256:72814c01533f51d68702802d74f77ea026b5ec52793c791e2da806a3844a46c3",
"sha256:7a4826ad2bd6b07ca615c74ab91f32f6c96d08f6fcc3902ceeedaec8cdc3bcd6",
"sha256:7c70087bfee18a42b4040bb9ec1ca15a08242cf5867c58726530bdf3945672ed",
"sha256:855eafa5d5a2034b4621c74925d89c5efef61418570e5ef9b37717d9c796419c",
"sha256:8700f06d0ce6f128de3ccdbc1acaea1ee264d2caa9ca05daaf492fde7c2a7200",
"sha256:89f1b185a01fe560bc8ae5f619e924407efca2191b56ce749ec84982fc59a32a",
"sha256:8b2c760cfc7042b27ebdb4a43a4453bd829a5742503599144d54a032c5dc7e9e",
"sha256:8c2f5e83493748286002f9369f3e6607c565a6a90425a3a1fef5ae32a36d749d",
"sha256:8e098148dd37b4ce3baca71fb394c81dc5d9c7728c95df695d2dca218edf40e6",
"sha256:94aea8eff76ee6d1cdacb07dd2123a68283cb5569e0250feab1240058f53b623",
"sha256:95eb302ff792e12aba9a8b8f8474ab229a83c103d74a750ec0bd1c1eea32e669",
"sha256:9bd9b3b31adcb054116447ea22caa61a285d92e94d710aa5ec97992ff5eb7cf3",
"sha256:9e608aafdb55eb9f255034709e20d5a83b6d60c054df0802fa9c9883d0a937aa",
"sha256:a103b3a7069b62f5d4890ae1b8f0597618f628b286b03d4bc9195230b154bfa9",
"sha256:a386ebe437176aab38c041de1260cd3ea459c6ce5263594399880bbc398225b2",
"sha256:a38856a971c602f98472050165cea2cdc97709240373041b69030be15047691f",
"sha256:a401b4598e5d3f4a9a811f3daf42ee2291790c7f9d74b18d75d6e21dda98a1a1",
"sha256:a7647ebdfb9682b7bb97e2a5e7cb6ae735b1c25008a70b906aecca294ee96cf4",
"sha256:aaf63899c94de41fe3cf934601b0f7ccb6b428c6e4eeb80da72c58eab077b19a",
"sha256:b0dac0ff919ba34d4df1b6131f59ce95b08b9065233446be7e459f95554c0dc8",
"sha256:baacc6aee0b2ef6f3d308e197b5d7a81c0e70b06beae1f1fcacffdbd124fe0e3",
"sha256:bf420121d4c8dce6b889f0e8e4ec0ca34b7f40186203f06a946fa0276ba54029",
"sha256:c04a46716adde8d927adb9457bbe39cf473e1e2c2f5d0a16ceb837e5d841ad4f",
"sha256:c0b21078a4b56965e2b12f247467b234734491897e99c1d51cee628da9786959",
"sha256:c1c76a1743432b4b60ab3358c937a3fe1341c828ae6194108a94c69028247f22",
"sha256:c4983bf937209c57240cff65906b18bb35e64ae872da6a0db937d7b4af845dd7",
"sha256:c4fb39a81950ec280984b3a44f5bd12819953dc5fa3a7e6fa7a80db5ee853952",
"sha256:c57921cda3a80d0f2b8aec7e25c8aa14479ea92b5b51b6876d975d925a2ea346",
"sha256:c8063cf17b19661471ecbdb3df1c84f24ad2e389e326ccaf89e3fb2484d8dd7e",
"sha256:ccd16eb18a849fd8dcb23e23380e2f0a354e8daa0c984b8a732d9cfaba3a776d",
"sha256:cd6dbe0238f7743d0efe563ab46294f54f9bc8f4b9bcf57c3c666cc5bc9d1299",
"sha256:d62e51710986674142526ab9f78663ca2b0726066ae26b78b22e0f5e571238dd",
"sha256:db901e2ac34c931d73054d9797383d0f8009991e723dab15109740a63e7f902a",
"sha256:e03b8895a6990c9ab2cdcd0f2fe44088ca1c65ae592b8f795c3294af00a461c3",
"sha256:e1c8a2f4c69e08e89632defbfabec2feb8a8d99edc9f89ce33c4b9e36ab63037",
"sha256:e4b749b9cc6ee664a3300bb3a273c1ca8068c46be705b6c31cf5d276f8628a94",
"sha256:e6a5bf2cba5ae1bb80b154ed68a3cfa2fa00fde979a7f50d6598d3e17d9ac20c",
"sha256:e857a2232ba53ae940d3456f7533ce6ca98b81917d47adc3c7fd55dad8fab858",
"sha256:ee4006268ed33370957f55bf2e6f4d263eaf4dc3cfc473d1d90baff6ed36ce4a",
"sha256:eef9df1eefada2c09a5e7a40991b9fc6ac6ef20b1372abd48d2794a316dc0449",
"sha256:f058f6963fd82eb143c692cecdc89e075fa0828db2e5b291070485390b2f1c9c",
"sha256:f25c229a6ba38a35ae6e25ca1264621cc25d4d38dca2942a7fce0b67a4efe918",
"sha256:f2a1d0fd4242bd8643ce6f98927cf9c04540af6efa92323e9d3124f57727bfc1",
"sha256:f7560358a6811e52e9c4d142d497f1a6e10103d3a6881f18d04dbce3729c0e2c",
"sha256:f779d3ad205f108d14e99bb3859aa7dd8e9c68874617c72354d7ecaec2a054ac",
"sha256:f87f746ee241d30d6ed93969de31e5ffd09a2961a051e60ae6bddde9ec3583aa"
],
"markers": "python_full_version >= '3.7.0'",
"version": "==3.2.0"
},
"colorama": {
"hashes": [
"sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44",
"sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"
],
"markers": "sys_platform == 'win32'",
"version": "==0.4.6"
},
"dbutils": {
"hashes": [
"sha256:8e48565b12ad2b4b1f214de0294deeb4b28578f5b2abb40d68c2924b64d7e007",
"sha256:fc162b564263354d99c585ba22ae5f094283dcfa1032f7e07e5f01815b976f1c"
],
"index": "pypi",
"version": "==3.0.3"
},
"ddt": {
"hashes": [
"sha256:e3c93b961a108b4f4d5a6c7f2263513d928baf3bb5b32af8e1c804bfb041141d",
"sha256:f71b348731b8c78c3100bffbd951a769fbd439088d1fdbb3841eee019af80acd"
],
"index": "pypi",
"version": "==1.6.0"
},
"decorator": {
"hashes": [
"sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330",
"sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186"
],
"markers": "python_version >= '3.5'",
"version": "==5.1.1"
},
"et-xmlfile": {
"hashes": [
"sha256:8eb9e2bc2f8c97e37a2dc85a09ecdcdec9d8a396530a6d5a33b30b9a92da0c5c",
"sha256:a2ba85d1d6a74ef63837eed693bcb89c3f752169b0e3e7ae5b16ca5e1b3deada"
],
"markers": "python_version >= '3.6'",
"version": "==1.1.0"
},
"faker": {
"hashes": [
"sha256:4b7d5cd0c898f0b64f88fbf0a35aac66762f2273446ba4a4e459985a2e5c8f8c",
"sha256:d1eb772faf4a7c458c90b19d3626c40ae3460bd665ad7f5fb7b089e31d1a6dcf"
],
"index": "pypi",
"version": "==19.1.0"
},
"idna": {
"hashes": [
"sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4",
"sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"
],
"markers": "python_version >= '3.5'",
"version": "==3.4"
},
"jsonpath": {
"hashes": [
"sha256:46d3fd2016cd5b842283d547877a02c418a0fe9aa7a6b0ae344115a2c990fef4"
],
"index": "pypi",
"version": "==0.82"
},
"jsonpath-ng": {
"hashes": [
"sha256:292a93569d74029ba75ac2dc3d3630fc0e17b2df26119a165fa1d498ca47bf65",
"sha256:a273b182a82c1256daab86a313b937059261b5c5f8c4fa3fc38b882b344dd567",
"sha256:f75b95dbecb8a0f3b86fd2ead21c2b022c3f5770957492b9b6196ecccfeb10aa"
],
"index": "pypi",
"version": "==1.5.3"
},
"loguru": {
"hashes": [
"sha256:1612053ced6ae84d7959dd7d5e431a0532642237ec21f7fd83ac73fe539e03e1",
"sha256:b93aa30099fa6860d4727f1b81f8718e965bb96253fa190fab2077aaad6d15d3"
],
"index": "pypi",
"version": "==0.7.0"
},
"natsort": {
"hashes": [
"sha256:45312c4a0e5507593da193dedd04abb1469253b601ecaf63445ad80f0a1ea581",
"sha256:4732914fb471f56b5cce04d7bae6f164a592c7712e1c85f9ef585e197299521c"
],
"index": "pypi",
"version": "==8.4.0"
},
"openpyxl": {
"hashes": [
"sha256:a6f5977418eff3b2d5500d54d9db50c8277a368436f4e4f8ddb1be3422870184",
"sha256:f91456ead12ab3c6c2e9491cf33ba6d08357d802192379bb482f1033ade496f5"
],
"index": "pypi",
"version": "==3.1.2"
},
"ply": {
"hashes": [
"sha256:00c7c1aaa88358b9c765b6d3000c6eec0ba42abca5351b095321aef446081da3",
"sha256:096f9b8350b65ebd2fd1346b12452efe5b9607f7482813ffca50c22722a807ce"
],
"version": "==3.11"
},
"pyasn1": {
"hashes": [
"sha256:87a2121042a1ac9358cabcaf1d07680ff97ee6404333bacca15f76aa8ad01a57",
"sha256:97b7290ca68e62a832558ec3976f15cbf911bf5d7c7039d8b861c2a0ece69fde"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'",
"version": "==0.5.0"
},
"pydes": {
"hashes": [
"sha256:e2ab8e21d2b83e90d90dbfdcb6fb8ac0000b813238b7ecaede04f8435c389012"
],
"index": "pypi",
"version": "==2.0.1"
},
"pymysql": {
"hashes": [
"sha256:4f13a7df8bf36a51e81dd9f3605fede45a4878fe02f9236349fd82a3f0612f96",
"sha256:8969ec6d763c856f7073c4c64662882675702efcb114b4bcbb955aea3a069fa7"
],
"index": "pypi",
"version": "==1.1.0"
},
"python-dateutil": {
"hashes": [
"sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86",
"sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==2.8.2"
},
"pyyaml": {
"hashes": [
"sha256:01b45c0191e6d66c470b6cf1b9531a771a83c1c4208272ead47a3ae4f2f603bf",
"sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293",
"sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b",
"sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57",
"sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b",
"sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4",
"sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07",
"sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba",
"sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9",
"sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287",
"sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513",
"sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0",
"sha256:432557aa2c09802be39460360ddffd48156e30721f5e8d917f01d31694216782",
"sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0",
"sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92",
"sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f",
"sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2",
"sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc",
"sha256:81957921f441d50af23654aa6c5e5eaf9b06aba7f0a19c18a538dc7ef291c5a1",
"sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c",
"sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86",
"sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4",
"sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c",
"sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34",
"sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b",
"sha256:afa17f5bc4d1b10afd4466fd3a44dc0e245382deca5b3c353d8b757f9e3ecb8d",
"sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c",
"sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb",
"sha256:bfaef573a63ba8923503d27530362590ff4f576c626d86a9fed95822a8255fd7",
"sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737",
"sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3",
"sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d",
"sha256:d4b0ba9512519522b118090257be113b9468d804b19d63c71dbcf4a48fa32358",
"sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53",
"sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78",
"sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803",
"sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a",
"sha256:dbad0e9d368bb989f4515da330b88a057617d16b6a8245084f1b05400f24609f",
"sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174",
"sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5"
],
"index": "pypi",
"version": "==6.0"
},
"requests": {
"hashes": [
"sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f",
"sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"
],
"index": "pypi",
"version": "==2.31.0"
},
"rsa": {
"hashes": [
"sha256:90260d9058e514786967344d0ef75fa8727eed8a7d2e43ce9f4bcf1b536174f7",
"sha256:e38464a49c6c85d7f1351b0126661487a7e0a14a50f1675ec50eb34d4f20ef21"
],
"index": "pypi",
"version": "==4.9"
},
"six": {
"hashes": [
"sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926",
"sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==1.16.0"
},
"urllib3": {
"hashes": [
"sha256:48e7fafa40319d358848e1bc6809b208340fafe2096f1725d05d67443d0483d1",
"sha256:bee28b5e56addb8226c96f7f13ac28cb4c301dd5ea8a6ca179c0b9835e032825"
],
"index": "pypi",
"version": "==2.0.3"
},
"win32-setctime": {
"hashes": [
"sha256:15cf5750465118d6929ae4de4eb46e8edae9a5634350c01ba582df868e932cb2",
"sha256:231db239e959c2fe7eb1d7dc129f11172354f98361c4fa2d6d2d7e278baa8aad"
],
"markers": "sys_platform == 'win32'",
"version": "==1.1.0"
}
},
"develop": {}
}

View File

@ -255,12 +255,12 @@
```python
# 可以写类可以写函数可以直接普通python语句
def setup(action):
print("获取action示例的属性", action.get_vars())
# 更新属性到action实例的属性中
action.update_vars("999", "99999")
print("获取所有的临时变量", action.get_variable())
print("将变量存到临时变量表中以便后续用例{{key}}使用", action.update_variable("key", "value"))
print("将函数存到临时变量表,以便后面调用{{setup_func()}}也可以", action.update_variable("setup_func", setup))
print("获取action示例的属性", action.get_variables())
# 更新属性到action实例的属性中
action.update_variables("999", "99999")
print("获取所有的临时变量", action.get_environments())
print("将变量存到临时变量表中以便后续用例{{key}}使用", action.update_environments("key", "value"))
print("将函数存到临时变量表,以便后面调用{{setup_func()}}也可以", action.update_environments("setup_func", setup))
# 调用方法

Binary file not shown.

View File

@ -18,47 +18,46 @@ from common.validation.validator import Validator
@singleton
class Action(Extractor, LoadScript, Validator):
def __init__(self, initialize_data=None, bif_functions=None):
super().__init__()
self.encrypt = EncryptData()
self.__vars = {}
self.set_variable(initialize_data)
self.set_bif_fun(bif_functions)
def execute_dynamic_code(self, item, code):
self.set_vars(item)
print("___self.get_vars()____", self.get_vars())
if code is not None:
try:
ast_obj = ast.parse(code, mode='exec')
compiled = compile(ast_obj, '<string>', 'exec')
exec(compiled, {"action": self})
except SyntaxError as e:
error_message = f'Syntax error in dynamic code: {e}'
self._handle_error(error_message)
except Exception as e:
error_message = f"Error executing dynamic code: {e}"
self._handle_error(error_message)
finally:
return self.__vars
return item
def _handle_error(self, error_message):
print(f'Error occurred: {error_message}')
def set_vars(self, item):
self.__vars = item
def update_vars(self, key, value):
self.__vars[f"{{{{{key}}}}}"] = value
def get_vars(self, key=None):
"""获取依赖表 或 依赖表中key对应的值"""
return self.__vars if not key else self.__vars.get(key)
def analysis_request(self, request_data, jp_dict, headers_crypto, headers, request_crypto):
# 提取请求参数信息
self.substitute_data(request_data, jp_dict=jp_dict)
# 请求头及body加密或者加签
headers, request_data = self.encrypt.encrypts(headers_crypto, headers, request_crypto, request_data)
return headers, request_data
def __init__(self, initialize_data=None, bif_functions=None):
super().__init__()
self.encrypt = EncryptData()
self.__variables = {}
self.set_environments(initialize_data)
self.set_bif_fun(bif_functions)
def execute_dynamic_code(self, item, code):
self.set_variables(item)
if code is not None:
try:
ast_obj = ast.parse(code, mode='exec')
compiled = compile(ast_obj, '<string>', 'exec')
exec(compiled, {"pm": self})
except SyntaxError as e:
error_message = f'Syntax error in dynamic code: {e}'
self._handle_error(error_message)
except Exception as e:
error_message = f"Error executing dynamic code: {e}"
self._handle_error(error_message)
finally:
return self.__variables
return item
def _handle_error(self, error_message):
print(f'Error occurred: {error_message}')
def set_variables(self, item):
self.__variables = item
def update_variables(self, key, value):
self.__variables[f"{{{{{key}}}}}"] = value
def get_variables(self, key=None):
"""获取依赖表 或 依赖表中key对应的值"""
return self.__variables if not key else self.__variables.get(key)
def analysis_request(self, request_data, jp_dict, headers_crypto, headers, request_crypto):
# 提取请求参数信息
self.substitute_data(request_data, jp_dict=jp_dict)
# 请求头及body加密或者加签
headers, request_data = self.encrypt.encrypts(headers_crypto, headers, request_crypto, request_data)
return headers, request_data

View File

@ -12,140 +12,140 @@ import sys
sys.path.append("../")
sys.path.append("./common")
from jsonpath_ng import parse
from common.variables import Variables
from common.environments import Environments
from common.data_extraction import logger
REPLACE_DICT = {
"null": None,
"True": True,
"false": False
"null": None,
"True": True,
"false": False
}
class DataExtractor(Variables):
class DataExtractor(Environments):
def __init__(self):
super().__init__()
@logger.log_decorator("提取参数出现了意想不到的错误!!")
def substitute_data(self, response, regex=None, keys=None, deps=None, jp_dict=None):
"""
方法接收一个正则表达式 regex 和一个关联参数表 deps用于从接口返回的数据中提取关联参数
它会从接口返回的数据中使用正则表达式 regex 和正则表达式返回结果的键列表 keys 提取数据并将其更新到关联参数表中
然后它会使用 subs_deps subs_lists 方法提取更多的关联参数最后它将更新后的关联参数表设置为 Environments 类的静态变量并将其返回
Args:
response: 被提取数据对象
regex: 正则表达式 r'"id": (\d+), "name": "(\w+)",'
keys: 接收正则表达式返回结果的key ["a", "b"]
deps: "name=data[0].name;ok=data[0].id;an=data[0].age[3].a"
jp_dict: jsonpath 提取方式入参{"k": "$.data", "x": "$.data[0].age[3].a"}
Returns:
"""
response = response
if not isinstance(response, (dict, str, list)):
logger.error(f"被提取对象非字典、非字符串、非列表不执行jsonpath提取被提取对象: {response}")
return {}
if regex and keys:
self.substitute_regex(response, regex, keys)
response = response if isinstance(response, (dict, list)) else json.loads(response)
if deps:
self.substitute_route(response, deps)
if jp_dict:
self.substitute_jsonpath(response, jp_dict)
def substitute_regex(self, response, regex, keys):
"""
方法用于使用正则表达式 regex 和正则表达式返回结果的键列表 keys 从接口返回的数据中提取数据并将其更新到关联参数表中
Args:
response:
regex: 正则表达式r'"id": (\d+), "name": "(\w+)",'
keys:结果键列表["a", "b"],
Returns:
def __init__(self):
super().__init__()
"""
response = json.dumps(response) if isinstance(response, (dict, list)) else response
match = re.search(regex, response)
if not match:
return {}
groups = match.groups()
for i, key in enumerate(keys):
try:
self.update_environments(key, groups[i])
except:
self.update_environments(key, None)
def substitute_route(self, response, route_str):
"""
想字典一样取值:name=data[0].name;ok=data[0].id;an=data[0].age
Args:
response:
route_str:
@logger.log_decorator("提取参数出现了意想不到的错误!!")
def substitute_data(self, response, regex=None, keys=None, deps=None, jp_dict=None):
"""
方法接收一个正则表达式 regex 和一个关联参数表 deps用于从接口返回的数据中提取关联参数
它会从接口返回的数据中使用正则表达式 regex 和正则表达式返回结果的键列表 keys 提取数据并将其更新到关联参数表中
然后它会使用 subs_deps subs_lists 方法提取更多的关联参数最后它将更新后的关联参数表设置为 Variables 类的静态变量并将其返回
Args:
response: 被提取数据对象
regex: 正则表达式 r'"id": (\d+), "name": "(\w+)",'
keys: 接收正则表达式返回结果的key ["a", "b"]
deps: "name=data[0].name;ok=data[0].id;an=data[0].age[3].a"
jp_dict: jsonpath 提取方式入参{"k": "$.data", "x": "$.data[0].age[3].a"}
Returns:
"""
Returns:
response = response
if not isinstance(response, (dict, str, list)):
logger.error(f"被提取对象非字典、非字符串、非列表不执行jsonpath提取被提取对象: {response}")
return {}
if regex and keys:
self.substitute_regex(response, regex, keys)
response = response if isinstance(response, (dict, list)) else json.loads(response)
if deps:
self.substitute_route(response, deps)
if jp_dict:
self.substitute_jsonpath(response, jp_dict)
"""
deps_list = re.sub(f"[\r\n]+", "", route_str).split(";")
for dep_item in deps_list:
key, value_path = dep_item.split("=")
value_path_parts = re.findall(r'\w+', value_path)
temp = response
for part in value_path_parts:
if isinstance(temp, dict):
temp = temp.get(part)
elif isinstance(temp, list):
if part.isdigit():
index = int(part)
if index < len(temp):
temp = temp[index]
else:
temp = None
break
else:
temp = None
break
else:
temp = None
break
if isinstance(temp, (dict, list)):
continue
else:
break
if temp is not None:
self.update_environments(key, temp)
def substitute_jsonpath(self, response, json_path_dict):
"""
jsonpath 提取参数
Args:
response: 响应结果
json_path_dict: {"k": "$.data", "x": "$.data[0].age[3].a"}
def substitute_regex(self, response, regex, keys):
"""
方法用于使用正则表达式 regex 和正则表达式返回结果的键列表 keys 从接口返回的数据中提取数据并将其更新到关联参数表中
Args:
response:
regex: 正则表达式r'"id": (\d+), "name": "(\w+)",'
keys:结果键列表["a", "b"],
Returns:
Returns: 字符串或者list
"""
response = json.dumps(response) if isinstance(response, (dict, list)) else response
match = re.search(regex, response)
if not match:
return {}
groups = match.groups()
for i, key in enumerate(keys):
try:
self.update_variable(key, groups[i])
except:
self.update_variable(key, None)
def substitute_route(self, response, route_str):
"""
想字典一样取值:name=data[0].name;ok=data[0].id;an=data[0].age
Args:
response:
route_str:
Returns:
"""
deps_list = re.sub(f"[\r\n]+", "", route_str).split(";")
for dep_item in deps_list:
key, value_path = dep_item.split("=")
value_path_parts = re.findall(r'\w+', value_path)
temp = response
for part in value_path_parts:
if isinstance(temp, dict):
temp = temp.get(part)
elif isinstance(temp, list):
if part.isdigit():
index = int(part)
if index < len(temp):
temp = temp[index]
else:
temp = None
break
else:
temp = None
break
else:
temp = None
break
if isinstance(temp, (dict, list)):
continue
else:
break
if temp is not None:
self.update_variable(key, temp)
def substitute_jsonpath(self, response, json_path_dict):
"""
jsonpath 提取参数
Args:
response: 响应结果
json_path_dict: {"k": "$.data", "x": "$.data[0].age[3].a"}
Returns: 字符串或者list
"""
json_path_dict = json_path_dict if isinstance(json_path_dict, dict) else json.loads(json_path_dict)
for key, expression in json_path_dict.items():
try:
parsed_expression = parse(expression)
data = response
# 使用解析器对象进行匹配和提取
match = parsed_expression.find(data)
result = [m.value for m in match]
self.update_variable(key, result[0]) if len(result) == 1 else self.update_variable(key,
result)
except Exception as e:
logger.error(f"jsonpath表达式错误'{expression}': {e}")
"""
json_path_dict = json_path_dict if isinstance(json_path_dict, dict) else json.loads(json_path_dict)
for key, expression in json_path_dict.items():
try:
parsed_expression = parse(expression)
data = response
# 使用解析器对象进行匹配和提取
match = parsed_expression.find(data)
result = [m.value for m in match]
self.update_environments(key, result[0]) if len(result) == 1 else self.update_environments(key,
result)
except Exception as e:
logger.error(f"jsonpath表达式错误'{expression}': {e}")
if __name__ == '__main__':
# 测试subs函数
res = '{"code": 1,"data": [{"id": 1, "name": "Alice", "age": [20, 21, 22, {"a": "b"}]}]}'
lists = {"k": "$..code", "x": "$.data[0].age[3].a"}
dep_str = "name=data[0].name;ok=data[0].id;an=data[0].age"
regex_str = r'"id": (\d+), "name": "(\w+)",'
regex_key = ["a", "b"]
t = DataExtractor()
t.substitute_data(res, regex=regex_str, keys=regex_key, deps=dep_str, jp_dict=lists)
print("-------->res:", t.get_variable())
# 测试subs函数
res = '{"code": 1,"data": [{"id": 1, "name": "Alice", "age": [20, 21, 22, {"a": "b"}]}]}'
lists = {"k": "$..code", "x": "$.data[0].age[3].a"}
dep_str = "name=data[0].name;ok=data[0].id;an=data[0].age"
regex_str = r'"id": (\d+), "name": "(\w+)",'
regex_key = ["a", "b"]
t = DataExtractor()
t.substitute_data(res, regex=regex_str, keys=regex_key, deps=dep_str, jp_dict=lists)
print("-------->res:", t.get_environments())

View File

@ -11,7 +11,7 @@ import json
from common.data_extraction import logger
# from common.http_client.http_client import Pyt
# from common.variables import
# from common.environments import
from common.data_extraction.data_extractor import DataExtractor
@ -45,10 +45,10 @@ class DependentParameter(DataExtractor):
if self.pattern_fun.search(jst):
# 函数替换
key = self.pattern_fun.search(jst).group()
if key in self.get_variable().keys():
if key in self.get_environments().keys():
# 如果参数名称存在于关联参数表中,则调用相应的函数获取返回值,并替换字符串中的参数
value_ = self.get_variable(key)()
value_ = self.get_environments(key)()
jst = jst.replace(key, str(value_))
else:
logger.error(
@ -65,11 +65,11 @@ class DependentParameter(DataExtractor):
index = ""
k = key.group()
# 如果参数名称存在于关联参数表中,则获取相应的值,并替换字符串中的参数
if k in self.get_variable().keys():
if k in self.get_environments().keys():
if isinstance(index, int):
value_ = self.get_variable(k)[index]
value_ = self.get_environments(k)[index]
else:
value_ = self.get_variable(k)
value_ = self.get_environments(k)
jst = jst.replace(key.group(), str(value_))
else:
logger.error(
@ -86,7 +86,7 @@ class DependentParameter(DataExtractor):
if __name__ == '__main__':
from common.variables import Variables
from common.environments import Environments
dps = {
"{{var_a}}": "foo",
@ -98,8 +98,8 @@ if __name__ == '__main__':
"{{var_g}}": {'g': 'gg', 'g1': 'gg', 'g2': 'gg2'}
}
d = Variables()
d.set_variable(dps)
d = Environments()
d.set_environments(dps)
from common.validation import loaders
from common import bif_functions

View File

@ -10,8 +10,8 @@
import json
import pymysql
from DBUtils.PooledDB import PooledDB
# from dbutils.pooled_db import PooledDB
# from DBUtils.PooledDB import PooledDB
from dbutils.pooled_db import PooledDB
from pymysql.cursors import DictCursor
from common.database import logger
@ -156,8 +156,8 @@ if __name__ == '__main__':
res = MysqlClient(database_2).execute_sql(sql_2)
print("数据执行结果", res)
from common.data_extraction.data_extractor import DataExtractor
from common.variables import Variables
from common.environments import Environments
t = DataExtractor()
t.substitute_data(res, jp_dict={"total": "$.select_sale[0].total", "total_1": "$..total"})
print(Variables.get_variable())
print(Environments.get_environments())

View File

@ -4,34 +4,34 @@ from dataclasses import dataclass
@dataclass
class Variables:
variables = {}
class Environments:
environments = {}
pattern_l = re.compile(r"{{\s*([^}\s]+)\s*}}(?:\[(\d+)\])?")
PATTERN = re.compile(r"{{(.*?)}}") # 预编译正则表达式
pattern = re.compile(r'({)')
pattern_fun = re.compile(r"{{(\w+\(\))}}")
@classmethod
def update_variable(cls, key, value):
def update_environments(cls, key, value):
"""更新依赖表"""
cls.variables[f"{{{{{key}}}}}"] = value
cls.environments[f"{{{{{key}}}}}"] = value
@classmethod
def get_variable(cls, key=None):
def get_environments(cls, key=None):
"""获取依赖表 或 依赖表中key对应的值"""
return cls.variables if not key else cls.variables.get(key)
return cls.environments if not key else cls.environments.get(key)
@classmethod
def set_variable(cls, value):
def set_environments(cls, value):
"""设置依赖表"""
cls.variables = value
cls.environments = value
@classmethod
def reset(cls):
def reset_environments(cls):
"""重置"""
cls.variables.clear()
cls.request = None
cls.response = None
# cls.request = None
# cls.response = None
cls.environments.clear()
if __name__ == '__main__':
@ -41,6 +41,6 @@ if __name__ == '__main__':
test_file = Config.test_case
do_excel = DoExcel(test_file)
init_case = do_excel.get_excel_init()
d = Variables
d.set_variable(init_case)
print("--------------------->", d.get_variable())
d = Environments
d.set_environments(init_case)
print("--------------------->", d.get_environments())

View File

@ -29,7 +29,7 @@ class Pyt(LoadModulesFromFolder):
def decorator(func):
def wrapper(*args, **kwargs):
try:
print(f"发送请求的参数==== {kwargs}")
print(f"发送请求的参数 {kwargs}")
response = func(*args, **kwargs)
print(f"请求地址 --> {response.request.url}")
print(f"请求头 --> {response.request.headers}")
@ -48,7 +48,7 @@ class Pyt(LoadModulesFromFolder):
# def pre_script(self,name):
# def decorator(func):
# self.variables = func
# self.environments = func
# return decorator
# @log_decorator()
@ -94,7 +94,6 @@ class Pyt(LoadModulesFromFolder):
('file', (f'{file_path}', f, file_type))
)
kwargs['files'] = files
print("=" * 30, kwargs)
# 发送请求
self.request = requests.Request(method, __url, **kwargs)

View File

@ -72,7 +72,7 @@ class MyLogger:
def __getattr__(self, level: str):
return getattr(self.logger, level)
def log_decorator(self, msg="快看,异常了,别唧唧哇哇,块排查"):
def log_decorator(self, msg="快看,异常了,别唧唧哇哇,快排查!!"):
"""
日志装饰器记录函数的名称参数返回值运行时间和异常信息
Args:

View File

@ -14,7 +14,7 @@ from common.data_extraction.dependent_parameter import DependentParameter
from common.validation import logger
# from common.variables import Variables
# from common.environments import Environments
# from common.data_extraction.data_extractor import DataExtractor
@ -52,10 +52,10 @@ class LoadModulesFromFolder(DependentParameter):
# 遍历 module 对象中的所有属性,找出函数并添加到 functions 字典中
for name, obj in vars(module).items():
if callable(obj):
self.update_variable(name, obj)
self.update_environments(name, obj)
if __name__ == '__main__':
lmff = LoadModulesFromFolder()
lmff.load_modules_from_folder(r'D:\apk_api\api-test-project\extensions')
print(lmff.get_variable())
print(lmff.get_environments())

View File

@ -30,8 +30,9 @@ class Loaders(Pyt):
built_in_functions[name] = item
return built_in_functions
@staticmethod
@logger.log_decorator()
def load_built_in_comparators(self) -> object:
def load_built_in_comparators() -> object:
"""
加载包中的内建比较器
Returns:
@ -44,16 +45,6 @@ class Loaders(Pyt):
return built_in_comparators
# def load_model_fun(model):
# """
# 加载指定模块中的所有函数
# Returns:
#
# """
# for name, item in __vars(model).items():
# if isinstance(item, types.FunctionType):
# Variables.update_variable(f"{name}()", item)
@logger.log_decorator()
def set_bif_fun(self, model):
"""
@ -62,13 +53,18 @@ class Loaders(Pyt):
"""
for k, v in self.load_built_in_functions(model).items():
self.update_variable(f"{k}()", v)
self.update_environments(f"{k}()", v)
if __name__ == '__main__':
from common.bif_functions import random_tools
import extensions
print()
loaders = Loaders()
loaders.load_built_in_comparators()
loaders.set_bif_fun(random_tools)
print(loaders.get_variable())
print(loaders.get_environments())
loaders.set_bif_fun(extensions)
print(loaders.get_environments())

View File

@ -14,123 +14,115 @@ from common.validation.extractor import Extractor
from common.validation.loaders import Loaders
# load_built_in_comparators
class Validator(Loaders):
"""
校验器
主要功能
1格式化校验变量
2校验期望结果与实际结果与预期一致并返回校验结果
"""
validate_variables_list = []
built_in_comparators = Loaders.load_built_in_comparators()
# built_in_comparators = self.load_built_in_comparators()
def __init__(self):
super().__init__()
# self.validate_variables_list = []
# self.built_in_comparators = self.load_built_in_comparators()
def uniform_validate(self, validate_variables):
"""
统一格式化测试用例的验证变量validate
Args:
validate_variables: 参数格式 listdict
示例
[{"check":"result.user.name","comparator":"eq","expect":"chenyongzhi"}]
or {"check":"result.user.name","comparator":"eq","expect":"chenyongzhi"}
"""
校验器
主要功能
1格式化校验变量
2校验期望结果与实际结果与预期一致并返回校验结果
"""
validate_variables_list = []
built_in_comparators = Loaders.load_built_in_comparators()
def __init__(self):
super().__init__()
def uniform_validate(self, validate_variables):
"""
统一格式化测试用例的验证变量validate
Args:
validate_variables: 参数格式 listdict
示例
[{"check":"result.user.name","comparator":"eq","expect":"chenyongzhi"}]
or {"check":"result.user.name","comparator":"eq","expect":"chenyongzhi"}
Returns: 返回数据格式 list
示例
[{"check":"result.user.name","comparator":"eq","expect":"chenyongzhi"}]
Returns: 返回数据格式 list
示例
[{"check":"result.user.name","comparator":"eq","expect":"chenyongzhi"}]
"""
if isinstance(validate_variables, str):
validate_variables = json.loads(validate_variables)
print("validate_variables>>>", validate_variables, type(validate_variables))
if isinstance(validate_variables, list):
for item in validate_variables:
self.uniform_validate(item)
elif isinstance(validate_variables, dict):
if "check" in validate_variables.keys() and "expect" in validate_variables.keys():
# 如果验证mapping中不包含comparator时默认为{"comparator": "eq"}
check_item = validate_variables.get("check")
expect_value = validate_variables.get("expect")
comparator = validate_variables.get("comparator", "eq")
self.validate_variables_list.append({
"check": check_item,
"expect": expect_value,
"comparator": comparator
})
else:
logger.error("参数格式错误!")
def validate(self, resp_obj=None):
"""
校验期望结果与实际结果与预期一致
Args:
resp_obj: ResponseObject对象实例
"""
if isinstance(validate_variables, str):
validate_variables = json.loads(validate_variables)
if isinstance(validate_variables, list):
for item in validate_variables:
self.uniform_validate(item)
elif isinstance(validate_variables, dict):
if "check" in validate_variables.keys() and "expect" in validate_variables.keys():
# 如果验证mapping中不包含comparator时默认为{"comparator": "eq"}
check_item = validate_variables.get("check")
expect_value = validate_variables.get("expect")
comparator = validate_variables.get("comparator", "eq")
self.validate_variables_list.append({
"check": check_item,
"expect": expect_value,
"comparator": comparator
})
else:
logger.error("参数格式错误!")
def validate(self, resp_obj=None):
"""
校验期望结果与实际结果与预期一致
Args:
resp_obj: ResponseObject对象实例
Returns:
Returns:
"""
validate_pass = "PASS"
# 记录校验失败的原因
failure_reason = []
for validate_variable in self.validate_variables_list:
check_item = validate_variable['check']
expect_value = validate_variable['expect']
comparator = validate_variable['comparator']
actual_value = Extractor.extract_value_by_jsonpath(resp_obj=resp_obj, expr=check_item)
try:
# 获取比较器
fun = self.built_in_comparators[comparator]
fun(actual_value=actual_value, expect_value=expect_value)
except (AssertionError, TypeError):
validate_pass = "FAIL"
failure_reason.append({
'检查项': check_item,
'期望值': expect_value,
'实际值': actual_value,
'断言方法': comparator_dict.get(comparator),
})
return validate_pass, failure_reason
def run_validate(self, validate_variables, resp_obj=None):
"""
统一格式化测试用例的验证变量validate然后校验期望结果与实际结果与预期一致
Args:
validate_variables:参数格式 listdict
resp_obj:ResponseObject对象实例
"""
validate_pass = "PASS"
# 记录校验失败的原因
failure_reason = []
for validate_variable in self.validate_variables_list:
check_item = validate_variable['check']
expect_value = validate_variable['expect']
comparator = validate_variable['comparator']
actual_value = Extractor.extract_value_by_jsonpath(resp_obj=resp_obj, expr=check_item)
try:
# 获取比较器
fun = self.built_in_comparators[comparator]
fun(actual_value=actual_value, expect_value=expect_value)
except (AssertionError, TypeError):
validate_pass = "FAIL"
failure_reason.append({
'检查项': check_item,
'期望值': expect_value,
'实际值': actual_value,
'断言方法': comparator_dict.get(comparator),
})
return validate_pass, failure_reason
def run_validate(self, validate_variables, resp_obj=None):
"""
统一格式化测试用例的验证变量validate然后校验期望结果与实际结果与预期一致
Args:
validate_variables:参数格式 listdict
resp_obj:ResponseObject对象实例
Returns:返回校验结果
Returns:返回校验结果
"""
if not validate_variables:
return ""
# 清空校验变量
self.validate_variables_list.clear()
self.uniform_validate(validate_variables)
if not self.validate_variables_list:
raise "uniform_validate 执行失败,无法进行 validate 校验"
return self.validate(resp_obj)
"""
if not validate_variables:
return ""
# 清空校验变量
self.validate_variables_list.clear()
self.uniform_validate(validate_variables)
if not self.validate_variables_list:
raise "uniform_validate 执行失败,无法进行 validate 校验"
return self.validate(resp_obj)
if __name__ == '__main__':
validate_variables1 = {"check": "$.result.user.name", "comparator": "eq", "expect": "chenyongzhi"}
validate_variables2 = [
{"check": "code", "comparator": "eq", "expect": "200"},
{"check": "result.user", "comparator": "eq", "expect": "chen5yongzhi"}
]
resp_obj = {"code": 200, "result": {"user": {"name": "chenyongzhi"}}}
validator = Validator()
print(validator.run_validate(validate_variables2, resp_obj))
# logger.info("---")
# validator.run_validate(validate_variables2, resp_obj)
# logger.info("---")
# validator.run_validate(validate_variables2, resp_obj)
# validate_variables1 = {"check": "$.result.user.name", "comparator": "eq", "expect": "chenyongzhi"}
validate_variables2 = [
{"check": "code", "comparator": "eq", "expect": "200"},
{"check": "result.user.name", "comparator": "eq", "expect": "chenyongzhi"}
]
resp_obj = {"code": "200", "result": {"user": {"name": "chenyongzhi"}}}
validator = Validator()
print(validator.run_validate(validate_variables2, resp_obj))
# logger.info("---")
# validator.run_validate(validate_variables2, resp_obj)
# logger.info("---")
# validator.run_validate(validate_variables2, resp_obj)

View File

@ -1,26 +1,19 @@
#!/usr/bin/env python
# encoding: utf-8
"""
@author: kira
@contact: 262667641@qq.com
@file: pm.py
@time: 2023/7/13 16:38
@desc:
"""
def setup(pm):
print("pm---------------->", pm.get_variables())
# request_data = pm.get_variables() # 获取得到请求数据
"""
request_data 的值: {'Url': '/login',
'Headers': '{"Content-Type": "application/json"}',
'Query Str': None,
'Request Data Type': 'params',
'Request Data': '{"account": "{{account}}", "password": "{{passwd}}"}',
'Expected': None, 'Response': '', 'Assertion': '', 'Error Log': ''
}
"""
BSP_TOKEN = pm.get_environments("{{BSP_TOKEN}}") # 获取环境变量
pm.update_environments("BSP_TOKEN_NEWS", BSP_TOKEN + "修改了环境变量") # 设置环境变量
print("---->pm.get_environments", pm.get_environments("{{BSP_TOKEN_NEWS}}"))
print("---->pm.get_variables", pm.get_variables())
def setup(action):
request_data = action.get_vars() # 获取得到请求数据
"""
request_data 的值: {'Url': '/login',
'Headers': '{"Content-Type": "application/json"}',
'Query Str': None,
'Request Data Type': 'params',
'Request Data': '{"account": "{{account}}", "password": "{{passwd}}"}',
'Expected': None, 'Response': '', 'Assertion': '', 'Error Log': ''
}
"""
#
email_str = action.get_variable("{{email()}}") # 加入已经自定义了邮件函数 则这里获取到
action.set_variable("userEmail", email_str)
setup(pm)

View File

@ -10,3 +10,6 @@
from common.utils.mylogger import MyLogger
logger = MyLogger()
from .dynamic_scaling_methods import *
from .sign import *

View File

@ -3,15 +3,23 @@
"""
@author: kira
@contact: 262667641@qq.com
@file: ext_method_online.py
@file: dynamic_scaling_methods.py
@time: 2023/3/27 8:40
@desc:
"""
__all__ = ["online_function"]
__all__ = ["online_function", "func1"]
# 用户自定义扩展函数文件。
def online_function():
pass
def func1():
pass
def func2():
pass

View File

@ -9,6 +9,7 @@ from common.config import Config
from common.database.mysql_client import MysqlClient
from common.file_handling.do_excel import DoExcel
from common.utils.mylogger import MyLogger
from extensions import dynamic_scaling_methods
test_file = Config.test_case # 获取 excel 文件路径
excel = DoExcel(test_file)
@ -24,172 +25,173 @@ host = init_data.get('host', "") + init_data.get("path", "")
@ddt
class TestProjectApi(unittest.TestCase):
maxDiff = None
action = Action(initialize_data, bif_functions)
@classmethod
def setUpClass(cls) -> None:
pass
#
@data(*test_case)
def test_api(self, item):
sheet, iid, condition, st, name, desc, h_crypto, r_crypto, method = self.__base_info(item)
regex, keys, deps, jp_dict, extract_request_data = self.__extractor_info(item)
setup_script, teardown_script = self.script(item)
if self.__is_run(condition):
return
self.__pause_execution(st)
# 首执行 sql
self.__exc_sql(item, method)
# 执行动态代码
item = self.action.execute_dynamic_code(item, setup_script)
# prepost_script = f"prepost_script_{sheet}_{iid}.py"
# item = self.action.load_and_execute_script(Config.SCRIPTS_DIR, prepost_script, "setup", item)
# 修正参数
item = self.action.replace_dependent_parameter(item)
print("*" * 15, item)
url, query_str, request_data, headers, expected, request_data_type = self.__request_info(item)
# 分析请求参数信息
headers, request_data = self.action.analysis_request(request_data, jp_dict, h_crypto, headers, r_crypto)
result_tuple = None
result = "PASS"
response = None
try:
# 执行请求操作
kwargs = {request_data_type: request_data, 'headers': headers, "params": query_str}
response = self.action.http_client(host, url, method, **kwargs)
# 执行后置代码片段
self.action.execute_dynamic_code(response, teardown_script)
# 执行断言 返回结果元组
result_tuple = self.action.run_validate(expected, response.json())
self.assertNotIn("FAIL", result_tuple, "FAIL 存在结果元组中")
try:
# 提取响应
self.action.substitute_data(response.json(), regex=regex, keys=keys, deps=deps, jp_dict=jp_dict)
except Exception as err:
logger.error(f"提取响应失败:{sheet}_{iid}_{name}_{desc}"
f"\nregex={regex};"
f" \nkeys={keys};"
f"\ndeps={deps};"
f"\njp_dict={jp_dict}"
f"\n{err}")
except Exception as e:
result = "FAIL"
logger.error(f'异常用例: {sheet}_{iid}_{name}_{desc}\n{e}')
raise e
finally:
response = response.text if response is not None else str(response)
# 响应结果及测试结果回写 excel
excel.write_back(sheet_name=sheet, i=iid, response=response, test_result=result,
assert_log=str(result_tuple))
@classmethod
def tearDownClass(cls) -> None:
excel.close_excel()
logger.info(f"所有用例执行完毕")
@staticmethod
def __base_info(item):
"""
获取基础信息
"""
sheet = item.pop("sheet")
item_id = item.pop("Id")
condition = item.pop("Run")
sleep_time = item.pop("Time")
name = item.pop("Name")
desc = item.pop("Description")
headers_crypto = item.pop("Headers Crypto")
request_data_crypto = item.pop("Request Data Crypto")
method = item.pop("Method")
return sheet, item_id, condition, sleep_time, name, desc, headers_crypto, request_data_crypto, method
@staticmethod
def __sql_info(item):
sql = item.pop("SQL")
sql_params_dict = item.pop("Sql Params Dict")
return sql, sql_params_dict
@staticmethod
def __extractor_info(item):
"""
获取提取参数的基本字段信息
Args:
item:
Returns:
"""
regex = item.pop("Regex")
keys = item.pop("Regex Params List")
deps = item.pop("Retrieve Value")
jp_dict = item.pop("Jsonpath")
extract_request_data = item.pop("Extract Request Data")
return regex, keys, deps, jp_dict, extract_request_data
@staticmethod
def __request_info(item):
"""
请求数据
"""
url = item.pop("Url")
query_str = item.pop("Query Str")
request_data = item.pop("Request Data")
headers = item.pop("Headers")
expected = item.pop("Expected")
request_data_type = item.pop("Request Data Type") if item.get("Request Data Type") else 'params'
return url, query_str, request_data, headers, expected, request_data_type
@staticmethod
def script(item):
setup_script = item.pop("Setup Script")
teardown_script = item.pop("Teardown Script")
return setup_script, teardown_script
@staticmethod
def __is_run(condition):
is_run = condition
if not is_run or is_run.upper() != "YES":
return True
@staticmethod
def __pause_execution(sleep_time):
if sleep_time:
try:
time.sleep(sleep_time)
except Exception as e:
logger.error("暂时时间必须是数字")
raise e
def __exc_sql(self, item, method):
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)
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
except Exception as e:
logger.error(f'执行 sql 失败:{sql},异常信息:{e}')
raise e
return sql
maxDiff = None
action = Action(initialize_data, bif_functions)
@classmethod
def setUpClass(cls) -> None:
pass
def setUp(self) -> None:
self.action.set_bif_fun(dynamic_scaling_methods)
@data(*test_case)
def test_api(self, item):
sheet, iid, condition, st, name, desc, h_crypto, r_crypto, method = self.__base_info(item)
regex, keys, deps, jp_dict, extract_request_data = self.__extractor_info(item)
setup_script, teardown_script = self.script(item)
if self.__is_run(condition):
return
self.__pause_execution(st)
# 首执行 sql
self.__exc_sql(item, method)
# 执行动态代码
item = self.action.execute_dynamic_code(item, setup_script)
# prepost_script = f"prepost_script_{sheet}_{iid}.py"
# item = self.action.load_and_execute_script(Config.SCRIPTS_DIR, prepost_script, "setup", item)
# 修正参数
item = self.action.replace_dependent_parameter(item)
url, query_str, request_data, headers, expected, request_data_type = self.__request_info(item)
# 分析请求参数信息
headers, request_data = self.action.analysis_request(request_data, jp_dict, h_crypto, headers, r_crypto)
result_tuple = None
result = "PASS"
response = None
try:
# 执行请求操作
kwargs = {request_data_type: request_data, 'headers': headers, "params": query_str}
response = self.action.http_client(host, url, method, **kwargs)
# 执行后置代码片段
self.action.execute_dynamic_code(response, teardown_script)
# 执行断言 返回结果元组
result_tuple = self.action.run_validate(expected, response.json())
self.assertNotIn("FAIL", result_tuple, "FAIL 存在结果元组中")
try:
# 提取响应
self.action.substitute_data(response.json(), regex=regex, keys=keys, deps=deps, jp_dict=jp_dict)
except Exception as err:
logger.error(f"提取响应失败:{sheet}_{iid}_{name}_{desc}"
f"\nregex={regex};"
f" \nkeys={keys};"
f"\ndeps={deps};"
f"\njp_dict={jp_dict}"
f"\n{err}")
except Exception as e:
result = "FAIL"
logger.error(f'异常用例: {sheet}_{iid}_{name}_{desc}\n{e}')
raise e
finally:
response = response.text if response is not None else str(response)
# 响应结果及测试结果回写 excel
excel.write_back(sheet_name=sheet, i=iid, response=response, test_result=result,
assert_log=str(result_tuple))
@classmethod
def tearDownClass(cls) -> None:
excel.close_excel()
logger.info(f"所有用例执行完毕")
@staticmethod
def __base_info(item):
"""
获取基础信息
"""
sheet = item.pop("sheet")
item_id = item.pop("Id")
condition = item.pop("Run")
sleep_time = item.pop("Time")
name = item.pop("Name")
desc = item.pop("Description")
headers_crypto = item.pop("Headers Crypto")
request_data_crypto = item.pop("Request Data Crypto")
method = item.pop("Method")
return sheet, item_id, condition, sleep_time, name, desc, headers_crypto, request_data_crypto, method
@staticmethod
def __sql_info(item):
sql = item.pop("SQL")
sql_params_dict = item.pop("Sql Params Dict")
return sql, sql_params_dict
@staticmethod
def __extractor_info(item):
"""
获取提取参数的基本字段信息
Args:
item:
Returns:
"""
regex = item.pop("Regex")
keys = item.pop("Regex Params List")
deps = item.pop("Retrieve Value")
jp_dict = item.pop("Jsonpath")
extract_request_data = item.pop("Extract Request Data")
return regex, keys, deps, jp_dict, extract_request_data
@staticmethod
def __request_info(item):
"""
请求数据
"""
url = item.pop("Url")
query_str = item.pop("Query Str")
request_data = item.pop("Request Data")
headers = item.pop("Headers")
expected = item.pop("Expected")
request_data_type = item.pop("Request Data Type") if item.get("Request Data Type") else 'params'
return url, query_str, request_data, headers, expected, request_data_type
@staticmethod
def script(item):
setup_script = item.pop("Setup Script")
teardown_script = item.pop("Teardown Script")
return setup_script, teardown_script
@staticmethod
def __is_run(condition):
is_run = condition
if not is_run or is_run.upper() != "YES":
return True
@staticmethod
def __pause_execution(sleep_time):
if sleep_time:
try:
time.sleep(sleep_time)
except Exception as e:
logger.error("暂时时间必须是数字")
raise e
def __exc_sql(self, item, method):
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)
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
except Exception as e:
logger.error(f'执行 sql 失败:{sql},异常信息:{e}')
raise e
return sql
if __name__ == '__main__':
unittest.main()
unittest.main()