api-engine-xin 0.0.21__tar.gz → 0.0.22__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {api_engine_xin-0.0.21 → api_engine_xin-0.0.22}/ApiEngine/BaseCase.py +20 -10
- {api_engine_xin-0.0.21 → api_engine_xin-0.0.22}/ApiEngine/caseLog.py +5 -0
- {api_engine_xin-0.0.21 → api_engine_xin-0.0.22}/ApiEngine/core.py +9 -3
- {api_engine_xin-0.0.21/api_engine_xin.egg-info → api_engine_xin-0.0.22}/PKG-INFO +2 -15
- {api_engine_xin-0.0.21 → api_engine_xin-0.0.22/api_engine_xin.egg-info}/PKG-INFO +3 -16
- {api_engine_xin-0.0.21 → api_engine_xin-0.0.22}/setup.py +1 -1
- {api_engine_xin-0.0.21 → api_engine_xin-0.0.22}/ApiEngine/__init__.py +0 -0
- {api_engine_xin-0.0.21 → api_engine_xin-0.0.22}/ApiEngine/dbClient.py +0 -0
- {api_engine_xin-0.0.21 → api_engine_xin-0.0.22}/ApiEngine/global_func.py +0 -0
- {api_engine_xin-0.0.21 → api_engine_xin-0.0.22}/ApiEngine/testResult.py +0 -0
- {api_engine_xin-0.0.21 → api_engine_xin-0.0.22}/LICENSE +0 -0
- {api_engine_xin-0.0.21 → api_engine_xin-0.0.22}/README.md +0 -0
- {api_engine_xin-0.0.21 → api_engine_xin-0.0.22}/api_engine_xin.egg-info/SOURCES.txt +0 -0
- {api_engine_xin-0.0.21 → api_engine_xin-0.0.22}/api_engine_xin.egg-info/dependency_links.txt +0 -0
- {api_engine_xin-0.0.21 → api_engine_xin-0.0.22}/api_engine_xin.egg-info/requires.txt +0 -0
- {api_engine_xin-0.0.21 → api_engine_xin-0.0.22}/api_engine_xin.egg-info/top_level.txt +0 -0
- {api_engine_xin-0.0.21 → api_engine_xin-0.0.22}/setup.cfg +0 -0
- {api_engine_xin-0.0.21 → api_engine_xin-0.0.22}/tests/Tools.py +0 -0
- {api_engine_xin-0.0.21 → api_engine_xin-0.0.22}/tests/__init__.py +0 -0
- {api_engine_xin-0.0.21 → api_engine_xin-0.0.22}/tests/runTest.py +0 -0
|
@@ -26,15 +26,17 @@ class BaseCase(CaseLogHandler):
|
|
|
26
26
|
db = self._db
|
|
27
27
|
# 1、读取前置脚本数据
|
|
28
28
|
setup_scripts = data.get("setup_script")
|
|
29
|
-
# 2、执行字符串中有效的python
|
|
30
|
-
|
|
29
|
+
# 2、执行字符串中有效的python代码(空值守卫)
|
|
30
|
+
if setup_scripts and isinstance(setup_scripts, str):
|
|
31
|
+
exec(setup_scripts)
|
|
31
32
|
|
|
32
33
|
response = yield
|
|
33
34
|
|
|
34
35
|
# 1、读取后置脚本数据
|
|
35
36
|
teardown_scripts = data.get("teardown_script")
|
|
36
|
-
# 2、执行字符串中有效的python
|
|
37
|
-
|
|
37
|
+
# 2、执行字符串中有效的python代码(空值守卫)
|
|
38
|
+
if teardown_scripts and isinstance(teardown_scripts, str):
|
|
39
|
+
exec(teardown_scripts)
|
|
38
40
|
|
|
39
41
|
yield
|
|
40
42
|
|
|
@@ -165,16 +167,17 @@ class BaseCase(CaseLogHandler):
|
|
|
165
167
|
else:
|
|
166
168
|
request_data["url"] = ENV.get("base_url") + data.get("interface").get("url")
|
|
167
169
|
request_data["method"] = data.get("interface").get("method")
|
|
168
|
-
# 2
|
|
169
|
-
request_data["headers"] = ENV.get("headers")
|
|
170
|
-
request_data["headers"].update(data.get("headers"))
|
|
170
|
+
# 2、处理请求头(使用副本,避免污染全局 ENV)
|
|
171
|
+
request_data["headers"] = dict(ENV.get("headers") or {})
|
|
172
|
+
request_data["headers"].update(data.get("headers") or {})
|
|
171
173
|
# 3、处理请求参数
|
|
172
174
|
request_data["params"] = data.get("request").get("params")
|
|
173
175
|
content_type = request_data["headers"].get("Content-Type", "")
|
|
176
|
+
_req = data.get("request") or {}
|
|
174
177
|
if "application/json" in content_type:
|
|
175
|
-
request_data["json"] =
|
|
178
|
+
request_data["json"] = _req.get("json") or _req.get("data")
|
|
176
179
|
if "application/x-www-form-urlencoded" in content_type or "multipart/form-data" in content_type:
|
|
177
|
-
request_data["data"] =
|
|
180
|
+
request_data["data"] = _req.get("data") or _req.get("json")
|
|
178
181
|
if "multipart/form-data" in content_type:
|
|
179
182
|
# 注意:这里不直接把 files 放进需要做变量替换的数据里,避免 open 文件对象被 eval 破坏
|
|
180
183
|
request_data["files"] = data.get("request").get("files")
|
|
@@ -223,6 +226,7 @@ class BaseCase(CaseLogHandler):
|
|
|
223
226
|
from urllib.parse import urlencode
|
|
224
227
|
query_string = urlencode(params)
|
|
225
228
|
full_url = f"{self.url}?{query_string}"
|
|
229
|
+
self.url = full_url # 更新 self.url 为完整URL(含已替换的查询参数)
|
|
226
230
|
self.info_log("请求地址:", full_url)
|
|
227
231
|
self.info_log("请求方法:", self.method)
|
|
228
232
|
self.info_log("请求头:", self.request_headers)
|
|
@@ -353,8 +357,11 @@ class BaseCase(CaseLogHandler):
|
|
|
353
357
|
self.error_log("响应体非JSON格式,无法提取数据")
|
|
354
358
|
# 3、通过 JSONPath 提取值
|
|
355
359
|
extracted_value = self.json_extract(resp_json, extract_expr)
|
|
360
|
+
# 记录实际值(供 __execute_assertions 读取,即使断言失败也能获取)
|
|
361
|
+
self._last_actual = extracted_value
|
|
356
362
|
# 4、断言
|
|
357
363
|
self.assertion(assertion_type, assertion_content, extracted_value)
|
|
364
|
+
return extracted_value
|
|
358
365
|
|
|
359
366
|
# 遍历所有assertions项,依次执行断言
|
|
360
367
|
def __execute_assertions(self, data, response):
|
|
@@ -368,12 +375,14 @@ class BaseCase(CaseLogHandler):
|
|
|
368
375
|
expected = assertion.get("expected", "未知")
|
|
369
376
|
assert_type = assertion.get("type", "eq")
|
|
370
377
|
passed = True
|
|
378
|
+
actual_value = None
|
|
371
379
|
try:
|
|
372
380
|
self.info_log(f" [{idx}/{total}] 执行断言: field={field}, expected={expected}")
|
|
373
|
-
self.__assert_data(assertion, response)
|
|
381
|
+
actual_value = self.__assert_data(assertion, response)
|
|
374
382
|
self.info_log(f" [{idx}/{total}] ✅ 断言通过: {field}")
|
|
375
383
|
except AssertionError as e:
|
|
376
384
|
passed = False
|
|
385
|
+
actual_value = getattr(self, '_last_actual', None)
|
|
377
386
|
self.error_log(f" [{idx}/{total}] ❌ 断言失败: {field} — {e}")
|
|
378
387
|
assertion_errors.append({
|
|
379
388
|
"index": idx,
|
|
@@ -387,6 +396,7 @@ class BaseCase(CaseLogHandler):
|
|
|
387
396
|
"field": field,
|
|
388
397
|
"type": assert_type,
|
|
389
398
|
"expected": expected,
|
|
399
|
+
"actual": actual_value,
|
|
390
400
|
"passed": passed,
|
|
391
401
|
})
|
|
392
402
|
# 所有断言执行完毕后输出汇总
|
|
@@ -1,7 +1,12 @@
|
|
|
1
|
+
import time
|
|
2
|
+
|
|
3
|
+
|
|
1
4
|
class CaseLogHandler:
|
|
2
5
|
"""用例日志处理类"""
|
|
3
6
|
def save_log(self,msg,level):
|
|
4
7
|
"""保存日志"""
|
|
8
|
+
ts = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time()))
|
|
9
|
+
msg = ts + " | " + msg
|
|
5
10
|
# 1、判断当前实例是否有日志属性
|
|
6
11
|
if not hasattr(self,"log_data"):
|
|
7
12
|
setattr(self,"log_data",[])
|
|
@@ -32,7 +32,9 @@ class TestRunner:
|
|
|
32
32
|
ENV.clear()
|
|
33
33
|
ENV.update(self.env_data)
|
|
34
34
|
# 将tools中的函数(用户自定义),通过exec执行(字符串中的python函数),加载到TestTools模块的命名空间中
|
|
35
|
-
|
|
35
|
+
_gf = ENV.get("global_func")
|
|
36
|
+
if _gf and isinstance(_gf, str):
|
|
37
|
+
exec(_gf, global_func.__dict__)
|
|
36
38
|
# 创建测试结果的记录器
|
|
37
39
|
test_result = TestResult(all=len(testcases["cases"]),name=testcases["name"])
|
|
38
40
|
# 运行测试用例
|
|
@@ -48,7 +50,9 @@ class TestRunner:
|
|
|
48
50
|
ENV.clear()
|
|
49
51
|
ENV.update(self.env_data)
|
|
50
52
|
# 将tools中的函数(用户自定义),通过exec执行(字符串中的python函数),加载到TestTools模块的命名空间中
|
|
51
|
-
|
|
53
|
+
_gf = ENV.get("global_func")
|
|
54
|
+
if _gf and isinstance(_gf, str):
|
|
55
|
+
exec(_gf, global_func.__dict__)
|
|
52
56
|
# 创建测试结果的记录器
|
|
53
57
|
test_result = TestResult(all=1)
|
|
54
58
|
# log.info_log("执行测试用例:",testcases)
|
|
@@ -65,7 +69,9 @@ class TestRunner:
|
|
|
65
69
|
ENV.clear()
|
|
66
70
|
ENV.update(self.env_data)
|
|
67
71
|
# 将tools中的函数(用户自定义),通过exec执行(字符串中的python函数),加载到TestTools模块的命名空间中
|
|
68
|
-
|
|
72
|
+
_gf = ENV.get("global_func")
|
|
73
|
+
if _gf and isinstance(_gf, str):
|
|
74
|
+
exec(_gf, global_func.__dict__)
|
|
69
75
|
# 新增检测日志
|
|
70
76
|
log.info_log(f"gen_random_num 是否存在:{hasattr(global_func, 'gen_random_num')}")
|
|
71
77
|
log.info_log(f"gen_random_num 是否可调用:{callable(getattr(global_func, 'gen_random_num', None))}")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
2
|
Name: api_engine_xin
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.22
|
|
4
4
|
Summary: 接口测试平台测试用例执行引擎
|
|
5
5
|
Home-page: https://pypi.org/project/api_engine_xin/
|
|
6
6
|
Author: Shawn
|
|
@@ -19,19 +19,6 @@ Classifier: Operating System :: OS Independent
|
|
|
19
19
|
Requires-Python: >=3.6
|
|
20
20
|
Description-Content-Type: text/markdown
|
|
21
21
|
License-File: LICENSE
|
|
22
|
-
Requires-Dist: pymysql>=1.0.0
|
|
23
|
-
Requires-Dist: requests>=2.26.0
|
|
24
|
-
Dynamic: author
|
|
25
|
-
Dynamic: author-email
|
|
26
|
-
Dynamic: classifier
|
|
27
|
-
Dynamic: description
|
|
28
|
-
Dynamic: description-content-type
|
|
29
|
-
Dynamic: home-page
|
|
30
|
-
Dynamic: keywords
|
|
31
|
-
Dynamic: license-file
|
|
32
|
-
Dynamic: requires-dist
|
|
33
|
-
Dynamic: requires-python
|
|
34
|
-
Dynamic: summary
|
|
35
22
|
|
|
36
23
|
|
|
37
24
|
# api_engine_xin
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
2
|
-
Name:
|
|
3
|
-
Version: 0.0.
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: api-engine-xin
|
|
3
|
+
Version: 0.0.22
|
|
4
4
|
Summary: 接口测试平台测试用例执行引擎
|
|
5
5
|
Home-page: https://pypi.org/project/api_engine_xin/
|
|
6
6
|
Author: Shawn
|
|
@@ -19,19 +19,6 @@ Classifier: Operating System :: OS Independent
|
|
|
19
19
|
Requires-Python: >=3.6
|
|
20
20
|
Description-Content-Type: text/markdown
|
|
21
21
|
License-File: LICENSE
|
|
22
|
-
Requires-Dist: pymysql>=1.0.0
|
|
23
|
-
Requires-Dist: requests>=2.26.0
|
|
24
|
-
Dynamic: author
|
|
25
|
-
Dynamic: author-email
|
|
26
|
-
Dynamic: classifier
|
|
27
|
-
Dynamic: description
|
|
28
|
-
Dynamic: description-content-type
|
|
29
|
-
Dynamic: home-page
|
|
30
|
-
Dynamic: keywords
|
|
31
|
-
Dynamic: license-file
|
|
32
|
-
Dynamic: requires-dist
|
|
33
|
-
Dynamic: requires-python
|
|
34
|
-
Dynamic: summary
|
|
35
22
|
|
|
36
23
|
|
|
37
24
|
# api_engine_xin
|
|
@@ -12,7 +12,7 @@ with codecs.open(os.path.join(here, "README.md"), encoding="utf-8") as fh:
|
|
|
12
12
|
# 核心配置
|
|
13
13
|
setup(
|
|
14
14
|
name="api_engine_xin", # ✅【必须改】pip install 这个名字!全网唯一,不能和PyPI上已有的包名重复
|
|
15
|
-
version="0.0.
|
|
15
|
+
version="0.0.22", # ✅【必须改】版本号,每次更新包都要升级版本(如0.0.2、0.1.0)
|
|
16
16
|
author="Shawn",# ✅【必须改】你的名字/昵称
|
|
17
17
|
author_email="xiaoh0525@xiaoh.com",# ✅【必须改】你的注册PyPI的邮箱
|
|
18
18
|
description="接口测试平台测试用例执行引擎", # ✅【必须改】一句话说明你的包是干嘛的
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{api_engine_xin-0.0.21 → api_engine_xin-0.0.22}/api_engine_xin.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|