api-engine-xin 0.0.20__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.20 → api_engine_xin-0.0.22}/ApiEngine/BaseCase.py +40 -10
- {api_engine_xin-0.0.20 → api_engine_xin-0.0.22}/ApiEngine/caseLog.py +5 -0
- {api_engine_xin-0.0.20 → api_engine_xin-0.0.22}/ApiEngine/core.py +9 -3
- api_engine_xin-0.0.22/ApiEngine/testResult.py +86 -0
- {api_engine_xin-0.0.20/api_engine_xin.egg-info → api_engine_xin-0.0.22}/PKG-INFO +2 -15
- {api_engine_xin-0.0.20 → api_engine_xin-0.0.22/api_engine_xin.egg-info}/PKG-INFO +3 -16
- {api_engine_xin-0.0.20 → api_engine_xin-0.0.22}/setup.py +1 -1
- api_engine_xin-0.0.20/ApiEngine/testResult.py +0 -109
- {api_engine_xin-0.0.20 → api_engine_xin-0.0.22}/ApiEngine/__init__.py +0 -0
- {api_engine_xin-0.0.20 → api_engine_xin-0.0.22}/ApiEngine/dbClient.py +0 -0
- {api_engine_xin-0.0.20 → api_engine_xin-0.0.22}/ApiEngine/global_func.py +0 -0
- {api_engine_xin-0.0.20 → api_engine_xin-0.0.22}/LICENSE +0 -0
- {api_engine_xin-0.0.20 → api_engine_xin-0.0.22}/README.md +0 -0
- {api_engine_xin-0.0.20 → api_engine_xin-0.0.22}/api_engine_xin.egg-info/SOURCES.txt +0 -0
- {api_engine_xin-0.0.20 → api_engine_xin-0.0.22}/api_engine_xin.egg-info/dependency_links.txt +0 -0
- {api_engine_xin-0.0.20 → api_engine_xin-0.0.22}/api_engine_xin.egg-info/requires.txt +0 -0
- {api_engine_xin-0.0.20 → api_engine_xin-0.0.22}/api_engine_xin.egg-info/top_level.txt +0 -0
- {api_engine_xin-0.0.20 → api_engine_xin-0.0.22}/setup.cfg +0 -0
- {api_engine_xin-0.0.20 → api_engine_xin-0.0.22}/tests/Tools.py +0 -0
- {api_engine_xin-0.0.20 → api_engine_xin-0.0.22}/tests/__init__.py +0 -0
- {api_engine_xin-0.0.20 → api_engine_xin-0.0.22}/tests/runTest.py +0 -0
|
@@ -13,6 +13,8 @@ class BaseCase(CaseLogHandler):
|
|
|
13
13
|
def __init__(self):
|
|
14
14
|
self.session = requests.Session()
|
|
15
15
|
self._db = None
|
|
16
|
+
self._extract_results = []
|
|
17
|
+
self._assert_results = []
|
|
16
18
|
|
|
17
19
|
def __run_script(self, data):
|
|
18
20
|
# 执行前后置脚本,可以在前后置脚本中共享数据
|
|
@@ -24,15 +26,17 @@ class BaseCase(CaseLogHandler):
|
|
|
24
26
|
db = self._db
|
|
25
27
|
# 1、读取前置脚本数据
|
|
26
28
|
setup_scripts = data.get("setup_script")
|
|
27
|
-
# 2、执行字符串中有效的python
|
|
28
|
-
|
|
29
|
+
# 2、执行字符串中有效的python代码(空值守卫)
|
|
30
|
+
if setup_scripts and isinstance(setup_scripts, str):
|
|
31
|
+
exec(setup_scripts)
|
|
29
32
|
|
|
30
33
|
response = yield
|
|
31
34
|
|
|
32
35
|
# 1、读取后置脚本数据
|
|
33
36
|
teardown_scripts = data.get("teardown_script")
|
|
34
|
-
# 2、执行字符串中有效的python
|
|
35
|
-
|
|
37
|
+
# 2、执行字符串中有效的python代码(空值守卫)
|
|
38
|
+
if teardown_scripts and isinstance(teardown_scripts, str):
|
|
39
|
+
exec(teardown_scripts)
|
|
36
40
|
|
|
37
41
|
yield
|
|
38
42
|
|
|
@@ -163,16 +167,17 @@ class BaseCase(CaseLogHandler):
|
|
|
163
167
|
else:
|
|
164
168
|
request_data["url"] = ENV.get("base_url") + data.get("interface").get("url")
|
|
165
169
|
request_data["method"] = data.get("interface").get("method")
|
|
166
|
-
# 2
|
|
167
|
-
request_data["headers"] = ENV.get("headers")
|
|
168
|
-
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 {})
|
|
169
173
|
# 3、处理请求参数
|
|
170
174
|
request_data["params"] = data.get("request").get("params")
|
|
171
175
|
content_type = request_data["headers"].get("Content-Type", "")
|
|
176
|
+
_req = data.get("request") or {}
|
|
172
177
|
if "application/json" in content_type:
|
|
173
|
-
request_data["json"] =
|
|
178
|
+
request_data["json"] = _req.get("json") or _req.get("data")
|
|
174
179
|
if "application/x-www-form-urlencoded" in content_type or "multipart/form-data" in content_type:
|
|
175
|
-
request_data["data"] =
|
|
180
|
+
request_data["data"] = _req.get("data") or _req.get("json")
|
|
176
181
|
if "multipart/form-data" in content_type:
|
|
177
182
|
# 注意:这里不直接把 files 放进需要做变量替换的数据里,避免 open 文件对象被 eval 破坏
|
|
178
183
|
request_data["files"] = data.get("request").get("files")
|
|
@@ -221,6 +226,7 @@ class BaseCase(CaseLogHandler):
|
|
|
221
226
|
from urllib.parse import urlencode
|
|
222
227
|
query_string = urlencode(params)
|
|
223
228
|
full_url = f"{self.url}?{query_string}"
|
|
229
|
+
self.url = full_url # 更新 self.url 为完整URL(含已替换的查询参数)
|
|
224
230
|
self.info_log("请求地址:", full_url)
|
|
225
231
|
self.info_log("请求方法:", self.method)
|
|
226
232
|
self.info_log("请求头:", self.request_headers)
|
|
@@ -311,6 +317,12 @@ class BaseCase(CaseLogHandler):
|
|
|
311
317
|
# 4、保存到环境变量(后续用 ${user_id} 引用)
|
|
312
318
|
self.save_env_variable(var_name, extracted_value)
|
|
313
319
|
self.info_log(f"数据提取成功:{var_name} = {extracted_value}")
|
|
320
|
+
# 5、记录提取结果
|
|
321
|
+
self._extract_results.append({
|
|
322
|
+
"var_name": var_name,
|
|
323
|
+
"extract_expr": extract_expr,
|
|
324
|
+
"value": extracted_value,
|
|
325
|
+
})
|
|
314
326
|
|
|
315
327
|
def __assert_data(self, assertion, response):
|
|
316
328
|
"""
|
|
@@ -345,8 +357,11 @@ class BaseCase(CaseLogHandler):
|
|
|
345
357
|
self.error_log("响应体非JSON格式,无法提取数据")
|
|
346
358
|
# 3、通过 JSONPath 提取值
|
|
347
359
|
extracted_value = self.json_extract(resp_json, extract_expr)
|
|
360
|
+
# 记录实际值(供 __execute_assertions 读取,即使断言失败也能获取)
|
|
361
|
+
self._last_actual = extracted_value
|
|
348
362
|
# 4、断言
|
|
349
363
|
self.assertion(assertion_type, assertion_content, extracted_value)
|
|
364
|
+
return extracted_value
|
|
350
365
|
|
|
351
366
|
# 遍历所有assertions项,依次执行断言
|
|
352
367
|
def __execute_assertions(self, data, response):
|
|
@@ -358,11 +373,16 @@ class BaseCase(CaseLogHandler):
|
|
|
358
373
|
for idx, assertion in enumerate(data.get("assertions"), start=1):
|
|
359
374
|
field = assertion.get("field", "未知")
|
|
360
375
|
expected = assertion.get("expected", "未知")
|
|
376
|
+
assert_type = assertion.get("type", "eq")
|
|
377
|
+
passed = True
|
|
378
|
+
actual_value = None
|
|
361
379
|
try:
|
|
362
380
|
self.info_log(f" [{idx}/{total}] 执行断言: field={field}, expected={expected}")
|
|
363
|
-
self.__assert_data(assertion, response)
|
|
381
|
+
actual_value = self.__assert_data(assertion, response)
|
|
364
382
|
self.info_log(f" [{idx}/{total}] ✅ 断言通过: {field}")
|
|
365
383
|
except AssertionError as e:
|
|
384
|
+
passed = False
|
|
385
|
+
actual_value = getattr(self, '_last_actual', None)
|
|
366
386
|
self.error_log(f" [{idx}/{total}] ❌ 断言失败: {field} — {e}")
|
|
367
387
|
assertion_errors.append({
|
|
368
388
|
"index": idx,
|
|
@@ -371,6 +391,14 @@ class BaseCase(CaseLogHandler):
|
|
|
371
391
|
"error_type": "ASSERTION_FAILED",
|
|
372
392
|
"message": str(e)
|
|
373
393
|
})
|
|
394
|
+
# 记录断言结果
|
|
395
|
+
self._assert_results.append({
|
|
396
|
+
"field": field,
|
|
397
|
+
"type": assert_type,
|
|
398
|
+
"expected": expected,
|
|
399
|
+
"actual": actual_value,
|
|
400
|
+
"passed": passed,
|
|
401
|
+
})
|
|
374
402
|
# 所有断言执行完毕后输出汇总
|
|
375
403
|
passed_count = total - len(assertion_errors)
|
|
376
404
|
if assertion_errors:
|
|
@@ -477,6 +505,8 @@ class BaseCase(CaseLogHandler):
|
|
|
477
505
|
"""执行用例"""
|
|
478
506
|
start_time = time.time()
|
|
479
507
|
self._precondition_errors = [] # 记录前置错误(供结果查询)
|
|
508
|
+
self._extract_results = [] # 重置提取结果
|
|
509
|
+
self._assert_results = [] # 重置断言结果
|
|
480
510
|
case_name = data.get('title')
|
|
481
511
|
has_failure = False # ★ 新增:失败标志位
|
|
482
512
|
try:
|
|
@@ -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))}")
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
from ApiEngine import log
|
|
2
|
+
from ApiEngine.BaseCase import BaseCase
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class TestResult:
|
|
6
|
+
"""测试结果类"""
|
|
7
|
+
def __init__(self, all, name="调试运行"):
|
|
8
|
+
"""
|
|
9
|
+
:param all: 测试套件中的用例个数
|
|
10
|
+
:param name: 测试套件的名称
|
|
11
|
+
"""
|
|
12
|
+
self.all = all
|
|
13
|
+
self.name = name
|
|
14
|
+
self.success = 0
|
|
15
|
+
self.fail = 0
|
|
16
|
+
self.error = 0
|
|
17
|
+
self.results = []
|
|
18
|
+
|
|
19
|
+
def _build_info(self, test: BaseCase, status: str) -> dict:
|
|
20
|
+
"""构建用例结果信息(包含提取和断言结果)"""
|
|
21
|
+
return {
|
|
22
|
+
"name": getattr(test, "name", ""),
|
|
23
|
+
"url": getattr(test, "url", ""),
|
|
24
|
+
"method": getattr(test, "method", ""),
|
|
25
|
+
"request_headers": getattr(test, "request_headers", ""),
|
|
26
|
+
"request_body": getattr(test, "request_body", ""),
|
|
27
|
+
"response_code": getattr(test, "status_code", ""),
|
|
28
|
+
"response_headers": getattr(test, "response_headers", ""),
|
|
29
|
+
"response_body": getattr(test, "response_body", ""),
|
|
30
|
+
"status": status,
|
|
31
|
+
"log_data": getattr(test, "log_data", ""),
|
|
32
|
+
"run_time": getattr(test, "elapsed_ms", ""),
|
|
33
|
+
"extract_info": getattr(test, "_extract_results", []),
|
|
34
|
+
"assert_info": getattr(test, "_assert_results", []),
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
def add_success(self, test: BaseCase):
|
|
38
|
+
"""
|
|
39
|
+
:param test: 用例对象
|
|
40
|
+
:return:
|
|
41
|
+
"""
|
|
42
|
+
self.success += 1
|
|
43
|
+
self.results.append(self._build_info(test, "success"))
|
|
44
|
+
|
|
45
|
+
def add_fail(self, test: BaseCase):
|
|
46
|
+
"""
|
|
47
|
+
:param test: 用例对象
|
|
48
|
+
:return:
|
|
49
|
+
"""
|
|
50
|
+
self.fail += 1
|
|
51
|
+
self.results.append(self._build_info(test, "fail"))
|
|
52
|
+
|
|
53
|
+
def add_error(self, test: BaseCase, error):
|
|
54
|
+
"""
|
|
55
|
+
:param test: 用例对象
|
|
56
|
+
:return:
|
|
57
|
+
"""
|
|
58
|
+
self.error += 1
|
|
59
|
+
# 同时记录到全局日志和当前用例日志,确保返回结果中也能看到 ERROR 记录
|
|
60
|
+
log.error_log("用例执行错误,错误信息:", error)
|
|
61
|
+
try:
|
|
62
|
+
test.error_log("用例执行错误,错误信息:", error)
|
|
63
|
+
except Exception:
|
|
64
|
+
pass
|
|
65
|
+
self.results.append(self._build_info(test, "error"))
|
|
66
|
+
|
|
67
|
+
def get_result_info(self):
|
|
68
|
+
"""
|
|
69
|
+
:return: 测试结果信息
|
|
70
|
+
"""
|
|
71
|
+
if self.success == self.all:
|
|
72
|
+
state = "success"
|
|
73
|
+
elif self.fail > 0:
|
|
74
|
+
state = "fail"
|
|
75
|
+
else:
|
|
76
|
+
state = "error"
|
|
77
|
+
info = {
|
|
78
|
+
"name": self.name,
|
|
79
|
+
"all": self.all,
|
|
80
|
+
"success": self.success,
|
|
81
|
+
"fail": self.fail,
|
|
82
|
+
"error": self.error,
|
|
83
|
+
"cases": self.results,
|
|
84
|
+
"state": state
|
|
85
|
+
}
|
|
86
|
+
return info
|
|
@@ -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="接口测试平台测试用例执行引擎", # ✅【必须改】一句话说明你的包是干嘛的
|
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
from ApiEngine import log
|
|
2
|
-
from ApiEngine.BaseCase import BaseCase
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
class TestResult:
|
|
6
|
-
"""测试结果类"""
|
|
7
|
-
def __init__(self, all, name="调试运行"):
|
|
8
|
-
"""
|
|
9
|
-
:param all: 测试套件中的用例个数
|
|
10
|
-
:param name: 测试套件的名称
|
|
11
|
-
"""
|
|
12
|
-
self.all = all
|
|
13
|
-
self.name = name
|
|
14
|
-
self.success = 0
|
|
15
|
-
self.fail = 0
|
|
16
|
-
self.error = 0
|
|
17
|
-
self.results = []
|
|
18
|
-
|
|
19
|
-
def add_success(self, test: BaseCase):
|
|
20
|
-
"""
|
|
21
|
-
:param test: 用例对象
|
|
22
|
-
:return:
|
|
23
|
-
"""
|
|
24
|
-
self.success += 1
|
|
25
|
-
info = {
|
|
26
|
-
"name": getattr(test, "name",""),
|
|
27
|
-
"url": getattr(test, "url",""),
|
|
28
|
-
"method": getattr(test, "method",""),
|
|
29
|
-
"request_headers": getattr(test, "request_headers",""),
|
|
30
|
-
"request_body": getattr(test, "request_body",""),
|
|
31
|
-
"response_code": getattr(test, "status_code",""),
|
|
32
|
-
"response_headers": getattr(test, "response_headers",""),
|
|
33
|
-
"response_body": getattr(test, "response_body",""),
|
|
34
|
-
"status": "success",
|
|
35
|
-
"log_data": getattr(test, "log_data", ""),
|
|
36
|
-
"run_time": getattr(test,"elapsed_ms","")
|
|
37
|
-
}
|
|
38
|
-
self.results.append(info)
|
|
39
|
-
|
|
40
|
-
def add_fail(self, test: BaseCase):
|
|
41
|
-
"""
|
|
42
|
-
:param test: 用例对象
|
|
43
|
-
:return:
|
|
44
|
-
"""
|
|
45
|
-
self.fail += 1
|
|
46
|
-
info = {
|
|
47
|
-
"name": getattr(test, "name",""),
|
|
48
|
-
"url": getattr(test, "url",""),
|
|
49
|
-
"method": getattr(test, "method",""),
|
|
50
|
-
"request_headers": getattr(test, "request_headers",""),
|
|
51
|
-
"request_body": getattr(test, "request_body",""),
|
|
52
|
-
"response_code": getattr(test, "status_code",""),
|
|
53
|
-
"response_headers": getattr(test, "response_headers",""),
|
|
54
|
-
"response_body": getattr(test, "response_body",""),
|
|
55
|
-
"status": "fail",
|
|
56
|
-
"log_data": getattr(test, "log_data", ""),
|
|
57
|
-
"run_time": getattr(test,"elapsed_ms","")
|
|
58
|
-
}
|
|
59
|
-
self.results.append(info)
|
|
60
|
-
|
|
61
|
-
def add_error(self, test: BaseCase, error):
|
|
62
|
-
"""
|
|
63
|
-
:param test: 用例对象
|
|
64
|
-
:return:
|
|
65
|
-
"""
|
|
66
|
-
self.error += 1
|
|
67
|
-
# 同时记录到全局日志和当前用例日志,确保返回结果中也能看到 ERROR 记录
|
|
68
|
-
log.error_log("用例执行错误,错误信息:", error)
|
|
69
|
-
try:
|
|
70
|
-
# BaseCase 继承了 CaseLogHandler,直接复用其 error_log 记录到用例的 log_data
|
|
71
|
-
test.error_log("用例执行错误,错误信息:", error)
|
|
72
|
-
except Exception:
|
|
73
|
-
# 如果 test 上不存在 error_log(理论上不会发生),则忽略,不影响后续结果生成
|
|
74
|
-
pass
|
|
75
|
-
info = {
|
|
76
|
-
"name": getattr(test, "name",""),
|
|
77
|
-
"url": getattr(test, "url",""),
|
|
78
|
-
"method": getattr(test, "method",""),
|
|
79
|
-
"request_headers": getattr(test, "request_headers",""),
|
|
80
|
-
"request_body": getattr(test, "request_body",""),
|
|
81
|
-
"response_code": getattr(test, "status_code",""),
|
|
82
|
-
"response_headers": getattr(test, "response_headers",""),
|
|
83
|
-
"response_body": getattr(test, "response_body",""),
|
|
84
|
-
"status": "error",
|
|
85
|
-
"log_data": getattr(test, "log_data", ""),
|
|
86
|
-
"run_time": getattr(test,"elapsed_ms","")
|
|
87
|
-
}
|
|
88
|
-
self.results.append(info)
|
|
89
|
-
|
|
90
|
-
def get_result_info(self):
|
|
91
|
-
"""
|
|
92
|
-
:return: 测试结果信息
|
|
93
|
-
"""
|
|
94
|
-
if self.success == self.all:
|
|
95
|
-
state = "success"
|
|
96
|
-
elif self.fail > 0:
|
|
97
|
-
state = "fail"
|
|
98
|
-
else:
|
|
99
|
-
state = "error"
|
|
100
|
-
info = {
|
|
101
|
-
"name": self.name,
|
|
102
|
-
"all": self.all,
|
|
103
|
-
"success": self.success,
|
|
104
|
-
"fail": self.fail,
|
|
105
|
-
"error": self.error,
|
|
106
|
-
"cases": self.results,
|
|
107
|
-
"state": state
|
|
108
|
-
}
|
|
109
|
-
return info
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{api_engine_xin-0.0.20 → 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
|