pytest-api-framework-alpha 0.3.8__tar.gz → 0.3.10__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.
- {pytest_api_framework_alpha-0.3.8 → pytest_api_framework_alpha-0.3.10}/PKG-INFO +1 -1
- {pytest_api_framework_alpha-0.3.8 → pytest_api_framework_alpha-0.3.10}/framework/conftest.py +31 -23
- pytest_api_framework_alpha-0.3.10/framework/utils/lark_util.py +87 -0
- {pytest_api_framework_alpha-0.3.8 → pytest_api_framework_alpha-0.3.10}/pytest_api_framework_alpha.egg-info/PKG-INFO +1 -1
- {pytest_api_framework_alpha-0.3.8 → pytest_api_framework_alpha-0.3.10}/setup.py +1 -1
- pytest_api_framework_alpha-0.3.8/framework/utils/lark_util.py +0 -71
- {pytest_api_framework_alpha-0.3.8 → pytest_api_framework_alpha-0.3.10}/framework/__init__.py +0 -0
- {pytest_api_framework_alpha-0.3.8 → pytest_api_framework_alpha-0.3.10}/framework/base_class.py +0 -0
- {pytest_api_framework_alpha-0.3.8 → pytest_api_framework_alpha-0.3.10}/framework/db/__init__.py +0 -0
- {pytest_api_framework_alpha-0.3.8 → pytest_api_framework_alpha-0.3.10}/framework/db/mysql_db.py +0 -0
- {pytest_api_framework_alpha-0.3.8 → pytest_api_framework_alpha-0.3.10}/framework/db/redis_db.py +0 -0
- {pytest_api_framework_alpha-0.3.8 → pytest_api_framework_alpha-0.3.10}/framework/exceptions.py +0 -0
- {pytest_api_framework_alpha-0.3.8 → pytest_api_framework_alpha-0.3.10}/framework/exit_code.py +0 -0
- {pytest_api_framework_alpha-0.3.8 → pytest_api_framework_alpha-0.3.10}/framework/extract.py +0 -0
- {pytest_api_framework_alpha-0.3.8 → pytest_api_framework_alpha-0.3.10}/framework/global_attribute.py +0 -0
- {pytest_api_framework_alpha-0.3.8 → pytest_api_framework_alpha-0.3.10}/framework/http_client.py +0 -0
- {pytest_api_framework_alpha-0.3.8 → pytest_api_framework_alpha-0.3.10}/framework/render_data.py +0 -0
- {pytest_api_framework_alpha-0.3.8 → pytest_api_framework_alpha-0.3.10}/framework/report.py +0 -0
- {pytest_api_framework_alpha-0.3.8 → pytest_api_framework_alpha-0.3.10}/framework/script.py +0 -0
- {pytest_api_framework_alpha-0.3.8 → pytest_api_framework_alpha-0.3.10}/framework/startapp.py +0 -0
- {pytest_api_framework_alpha-0.3.8 → pytest_api_framework_alpha-0.3.10}/framework/utils/__init__.py +0 -0
- {pytest_api_framework_alpha-0.3.8 → pytest_api_framework_alpha-0.3.10}/framework/utils/common.py +0 -0
- {pytest_api_framework_alpha-0.3.8 → pytest_api_framework_alpha-0.3.10}/framework/utils/date_util.py +0 -0
- {pytest_api_framework_alpha-0.3.8 → pytest_api_framework_alpha-0.3.10}/framework/utils/encrypt.py +0 -0
- {pytest_api_framework_alpha-0.3.8 → pytest_api_framework_alpha-0.3.10}/framework/utils/log_util.py +0 -0
- {pytest_api_framework_alpha-0.3.8 → pytest_api_framework_alpha-0.3.10}/framework/utils/mock_util.py +0 -0
- {pytest_api_framework_alpha-0.3.8 → pytest_api_framework_alpha-0.3.10}/framework/utils/yaml_util.py +0 -0
- {pytest_api_framework_alpha-0.3.8 → pytest_api_framework_alpha-0.3.10}/framework/validate.py +0 -0
- {pytest_api_framework_alpha-0.3.8 → pytest_api_framework_alpha-0.3.10}/pytest_api_framework_alpha.egg-info/SOURCES.txt +0 -0
- {pytest_api_framework_alpha-0.3.8 → pytest_api_framework_alpha-0.3.10}/pytest_api_framework_alpha.egg-info/dependency_links.txt +0 -0
- {pytest_api_framework_alpha-0.3.8 → pytest_api_framework_alpha-0.3.10}/pytest_api_framework_alpha.egg-info/requires.txt +0 -0
- {pytest_api_framework_alpha-0.3.8 → pytest_api_framework_alpha-0.3.10}/pytest_api_framework_alpha.egg-info/top_level.txt +0 -0
- {pytest_api_framework_alpha-0.3.8 → pytest_api_framework_alpha-0.3.10}/setup.cfg +0 -0
{pytest_api_framework_alpha-0.3.8 → pytest_api_framework_alpha-0.3.10}/framework/conftest.py
RENAMED
|
@@ -3,6 +3,7 @@ import re
|
|
|
3
3
|
import sys
|
|
4
4
|
import copy
|
|
5
5
|
import time
|
|
6
|
+
import platform
|
|
6
7
|
import threading
|
|
7
8
|
import importlib
|
|
8
9
|
import traceback
|
|
@@ -206,14 +207,14 @@ def pytest_generate_tests(metafunc):
|
|
|
206
207
|
if scenarios:
|
|
207
208
|
ids = list()
|
|
208
209
|
for index, item in enumerate(scenarios):
|
|
209
|
-
if item.get("scenario").get("ignore"):
|
|
210
|
-
continue
|
|
211
|
-
if func_name in item.get("scenario").get("exclude", list()):
|
|
212
|
-
continue
|
|
213
210
|
scenario = item.get("scenario")
|
|
214
211
|
level = scenario.get("level", settings.DEFAULT_CASE_LEVEL).lower()
|
|
215
|
-
|
|
216
212
|
case_data["level"] = level
|
|
213
|
+
if scenario.get("ignore"):
|
|
214
|
+
continue
|
|
215
|
+
if func_name in scenario.get("exclude", list()):
|
|
216
|
+
continue
|
|
217
|
+
|
|
217
218
|
new_marks = marks.copy()
|
|
218
219
|
new_marks.append(level)
|
|
219
220
|
# mark标记
|
|
@@ -246,11 +247,10 @@ def pytest_generate_tests(metafunc):
|
|
|
246
247
|
logger.error(f"scenario参数化格式不正确:{e}")
|
|
247
248
|
traceback.print_exc()
|
|
248
249
|
pytest.exit(ExitCode.SCENARIO_FORMAT_ERROR)
|
|
250
|
+
if case_data_list:
|
|
251
|
+
metafunc.parametrize("data", case_data_list, ids=ids, scope="function")
|
|
249
252
|
|
|
250
|
-
metafunc.parametrize("data", case_data_list, ids=ids, scope="function")
|
|
251
253
|
else:
|
|
252
|
-
if case_common.get("ignore"):
|
|
253
|
-
return
|
|
254
254
|
case_data["_scenario"] = {"data": {}}
|
|
255
255
|
case_data["_ignore_failed"] = case_common.get("ignore_failed", settings.GLOBAL_IGNORE_FAILED)
|
|
256
256
|
level = case_data.get("level", settings.DEFAULT_CASE_LEVEL)
|
|
@@ -523,13 +523,19 @@ def pytest_terminal_summary(terminalreporter, exitstatus, config):
|
|
|
523
523
|
terminalreporter.write(f"跳过用例数: {skipped}\n", yellow=True, bold=True)
|
|
524
524
|
terminalreporter.write(f"用例通过率: {pass_rate}%\n", green=True, bold=True)
|
|
525
525
|
terminalreporter.write("====================================\n", blue=True, bold=True)
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
526
|
+
if settings.ONLY_LINUX_NOTIFICATION:
|
|
527
|
+
if "linux" not in platform.platform().lower():
|
|
528
|
+
return
|
|
529
|
+
for webhook in settings.LARK_WEBHOOKS:
|
|
530
|
+
LarkUtil(webhook).send_test_report(
|
|
531
|
+
total=total,
|
|
532
|
+
passed=passed,
|
|
533
|
+
failed=failed,
|
|
534
|
+
skipped=skipped,
|
|
535
|
+
report_url=os.environ.get("ALLURE_REPORT_URL"),
|
|
536
|
+
job_name=os.environ.get("JOB_NAME"),
|
|
537
|
+
env=CONTEXT.get("env")
|
|
538
|
+
)
|
|
533
539
|
|
|
534
540
|
|
|
535
541
|
def pytest_exception_interact(node, call, report):
|
|
@@ -809,28 +815,30 @@ def sort(case_items):
|
|
|
809
815
|
|
|
810
816
|
# 根据组数 创建各组的数组 并插入第一个case
|
|
811
817
|
case_dict = dict()
|
|
812
|
-
|
|
813
|
-
|
|
818
|
+
|
|
819
|
+
for i in range(case_suite_num):
|
|
820
|
+
try:
|
|
814
821
|
item = ori_name_list[i][1]
|
|
815
822
|
id = item.callspec.id
|
|
816
823
|
|
|
817
824
|
first_part = id.split('#', 1)[-1]
|
|
818
825
|
index = first_part.split(']')[0]
|
|
819
826
|
case_dict[index] = [item]
|
|
820
|
-
|
|
821
|
-
|
|
827
|
+
except Exception as e:
|
|
828
|
+
continue
|
|
822
829
|
|
|
823
830
|
new_start_index = case_suite_num
|
|
824
831
|
# 以new_start_index为起点 重新遍历items
|
|
825
|
-
|
|
826
|
-
|
|
832
|
+
|
|
833
|
+
for i in range(new_start_index, len(non_custom_scope_items)):
|
|
834
|
+
try:
|
|
827
835
|
item = non_custom_scope_items[i]
|
|
828
836
|
id = item.callspec.id
|
|
829
837
|
first_part = id.split('#', 1)[-1]
|
|
830
838
|
index = first_part.split(']')[0]
|
|
831
839
|
case_dict.get(index).append(item)
|
|
832
|
-
|
|
833
|
-
|
|
840
|
+
except Exception as e:
|
|
841
|
+
continue
|
|
834
842
|
|
|
835
843
|
index = 0
|
|
836
844
|
for id in case_dict:
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import base64
|
|
2
|
+
import hmac
|
|
3
|
+
import hashlib
|
|
4
|
+
import time
|
|
5
|
+
from datetime import datetime
|
|
6
|
+
|
|
7
|
+
import json
|
|
8
|
+
import requests
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class LarkUtil:
|
|
12
|
+
def __init__(self, webhook: dict):
|
|
13
|
+
self.webhook = webhook
|
|
14
|
+
self.url = self.webhook.get("url")
|
|
15
|
+
self.secret = self.webhook.get("secret")
|
|
16
|
+
self.at_ids = self.webhook.get("open_ids") or None
|
|
17
|
+
self.headers = {"Content-Type": "application/json"}
|
|
18
|
+
|
|
19
|
+
@staticmethod
|
|
20
|
+
def gen_sign(timestamp, secret):
|
|
21
|
+
"""生成HMAC签名"""
|
|
22
|
+
# 拼接timestamp和secret
|
|
23
|
+
string_to_sign = '{}\n{}'.format(timestamp, secret)
|
|
24
|
+
hmac_code = hmac.new(string_to_sign.encode("utf-8"), digestmod=hashlib.sha256).digest()
|
|
25
|
+
# 对结果进行base64处理
|
|
26
|
+
sign = base64.b64encode(hmac_code).decode('utf-8')
|
|
27
|
+
return sign
|
|
28
|
+
|
|
29
|
+
def send_text(self, text: str, at_ids: list[str] = None):
|
|
30
|
+
data = {
|
|
31
|
+
"msg_type": "text",
|
|
32
|
+
"content": {"text": text},
|
|
33
|
+
}
|
|
34
|
+
if at_ids:
|
|
35
|
+
data["at"] = {"open_ids": at_ids}
|
|
36
|
+
if self.secret:
|
|
37
|
+
timestamp = str(int(time.time()))
|
|
38
|
+
data["sign"] = LarkUtil.gen_sign(timestamp, self.secret)
|
|
39
|
+
data["timestamp"] = timestamp
|
|
40
|
+
|
|
41
|
+
return requests.post(self.url, data=json.dumps(data), headers=self.headers)
|
|
42
|
+
|
|
43
|
+
def send_markdown(self, title: str, markdown_text: str, at_ids: list[str] = None):
|
|
44
|
+
"""发送 Markdown 消息"""
|
|
45
|
+
|
|
46
|
+
data = {
|
|
47
|
+
"msg_type": "interactive",
|
|
48
|
+
"card": {
|
|
49
|
+
"header": {
|
|
50
|
+
"template": "blue",
|
|
51
|
+
"title": {"tag": "plain_text", "content": title}
|
|
52
|
+
},
|
|
53
|
+
"elements": [
|
|
54
|
+
{
|
|
55
|
+
"tag": "markdown",
|
|
56
|
+
"content": markdown_text
|
|
57
|
+
}
|
|
58
|
+
]
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
if at_ids:
|
|
62
|
+
data["at"] = {"open_ids": at_ids}
|
|
63
|
+
if self.secret:
|
|
64
|
+
timestamp = str(int(time.time()))
|
|
65
|
+
data["sign"] = LarkUtil.gen_sign(timestamp, self.secret)
|
|
66
|
+
data["timestamp"] = timestamp
|
|
67
|
+
return requests.post(self.url, headers=self.headers, data=json.dumps(data))
|
|
68
|
+
|
|
69
|
+
def send_test_report(self, total: int, passed: int, failed: int, skipped: int, report_url: str = None,
|
|
70
|
+
job_name: str = None, env=None):
|
|
71
|
+
"""自动化测试结果消息(Markdown)"""
|
|
72
|
+
try:
|
|
73
|
+
pass_rate = round(passed / (total - skipped) * 100, 2)
|
|
74
|
+
except ZeroDivisionError:
|
|
75
|
+
pass_rate = 0
|
|
76
|
+
markdown = f"""**执行环境:** {env}
|
|
77
|
+
**执行完成时间:** {datetime.now().strftime("%Y-%m-%d %X")}
|
|
78
|
+
**执行用例总数:** {total}
|
|
79
|
+
**通过用例数:** {passed}
|
|
80
|
+
**失败用例数:** {failed}
|
|
81
|
+
**跳过用例数:** {skipped}
|
|
82
|
+
**用例通过率:** {pass_rate}%
|
|
83
|
+
"""
|
|
84
|
+
if report_url:
|
|
85
|
+
markdown += f"\n**测试报告:** [点击查看测试报告]({report_url})"
|
|
86
|
+
title = f"【自动化测试结果】-{job_name} " if job_name else "【自动化测试结果】"
|
|
87
|
+
return self.send_markdown(title, markdown)
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
import requests
|
|
2
|
-
import json
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
class LarkUtil:
|
|
6
|
-
def __init__(self, webhook: str):
|
|
7
|
-
self.webhook = webhook
|
|
8
|
-
self.headers = {"Content-Type": "application/json"}
|
|
9
|
-
|
|
10
|
-
def send_text(self, text: str, at_ids=None):
|
|
11
|
-
data = {
|
|
12
|
-
"msg_type": "text",
|
|
13
|
-
"content": {"text": text},
|
|
14
|
-
}
|
|
15
|
-
if at_ids:
|
|
16
|
-
data["at"] = {"open_ids": at_ids}
|
|
17
|
-
return requests.post(self.webhook, data=json.dumps(data), headers=self.headers)
|
|
18
|
-
|
|
19
|
-
def send_markdown(self, title: str, markdown_text: str):
|
|
20
|
-
"""发送 Markdown 消息"""
|
|
21
|
-
|
|
22
|
-
data = {
|
|
23
|
-
"msg_type": "interactive",
|
|
24
|
-
"card": {
|
|
25
|
-
"header": {
|
|
26
|
-
"template": "blue",
|
|
27
|
-
"title": {"tag": "plain_text", "content": title}
|
|
28
|
-
},
|
|
29
|
-
"elements": [
|
|
30
|
-
{
|
|
31
|
-
"tag": "markdown",
|
|
32
|
-
"content": markdown_text
|
|
33
|
-
}
|
|
34
|
-
]
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
resp = requests.post(self.webhook, headers=self.headers, data=json.dumps(data))
|
|
39
|
-
return resp.text
|
|
40
|
-
|
|
41
|
-
def send_test_report(self, total: int, passed: int, failed: int, skipped: int, report_url: str = None):
|
|
42
|
-
"""自动化测试结果消息(Markdown)"""
|
|
43
|
-
try:
|
|
44
|
-
pass_rate = round(passed / (total - skipped) * 100, 2)
|
|
45
|
-
except ZeroDivisionError:
|
|
46
|
-
pass_rate = 0
|
|
47
|
-
markdown = f"""
|
|
48
|
-
**执行统计:**
|
|
49
|
-
**执行用例总数:** {total}
|
|
50
|
-
**通过用例数:** {passed}
|
|
51
|
-
**失败用例数:** {failed}
|
|
52
|
-
**跳过用例数:** {skipped}
|
|
53
|
-
**用例通过率:** {pass_rate}%
|
|
54
|
-
"""
|
|
55
|
-
if report_url:
|
|
56
|
-
markdown += f"\n\t**测试报告:** 👉 [点击查看测试报告]({report_url})"
|
|
57
|
-
return self.send_markdown("自动化测试结果", markdown)
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
if __name__ == "__main__":
|
|
61
|
-
# 你的飞书群机器人 Webhook URL
|
|
62
|
-
WEBHOOK = "https://open.larksuite.com/open-apis/bot/v2/hook/27de2bf2-fa0d-49e7-8ff3-a3e3ad8cf2d7"
|
|
63
|
-
bot = LarkUtil(WEBHOOK)
|
|
64
|
-
|
|
65
|
-
bot.send_test_report(
|
|
66
|
-
total=20,
|
|
67
|
-
passed=18,
|
|
68
|
-
failed=1,
|
|
69
|
-
skipped=1,
|
|
70
|
-
report_url="http://your-report/index.html"
|
|
71
|
-
)
|
{pytest_api_framework_alpha-0.3.8 → pytest_api_framework_alpha-0.3.10}/framework/__init__.py
RENAMED
|
File without changes
|
{pytest_api_framework_alpha-0.3.8 → pytest_api_framework_alpha-0.3.10}/framework/base_class.py
RENAMED
|
File without changes
|
{pytest_api_framework_alpha-0.3.8 → pytest_api_framework_alpha-0.3.10}/framework/db/__init__.py
RENAMED
|
File without changes
|
{pytest_api_framework_alpha-0.3.8 → pytest_api_framework_alpha-0.3.10}/framework/db/mysql_db.py
RENAMED
|
File without changes
|
{pytest_api_framework_alpha-0.3.8 → pytest_api_framework_alpha-0.3.10}/framework/db/redis_db.py
RENAMED
|
File without changes
|
{pytest_api_framework_alpha-0.3.8 → pytest_api_framework_alpha-0.3.10}/framework/exceptions.py
RENAMED
|
File without changes
|
{pytest_api_framework_alpha-0.3.8 → pytest_api_framework_alpha-0.3.10}/framework/exit_code.py
RENAMED
|
File without changes
|
|
File without changes
|
{pytest_api_framework_alpha-0.3.8 → pytest_api_framework_alpha-0.3.10}/framework/global_attribute.py
RENAMED
|
File without changes
|
{pytest_api_framework_alpha-0.3.8 → pytest_api_framework_alpha-0.3.10}/framework/http_client.py
RENAMED
|
File without changes
|
{pytest_api_framework_alpha-0.3.8 → pytest_api_framework_alpha-0.3.10}/framework/render_data.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pytest_api_framework_alpha-0.3.8 → pytest_api_framework_alpha-0.3.10}/framework/startapp.py
RENAMED
|
File without changes
|
{pytest_api_framework_alpha-0.3.8 → pytest_api_framework_alpha-0.3.10}/framework/utils/__init__.py
RENAMED
|
File without changes
|
{pytest_api_framework_alpha-0.3.8 → pytest_api_framework_alpha-0.3.10}/framework/utils/common.py
RENAMED
|
File without changes
|
{pytest_api_framework_alpha-0.3.8 → pytest_api_framework_alpha-0.3.10}/framework/utils/date_util.py
RENAMED
|
File without changes
|
{pytest_api_framework_alpha-0.3.8 → pytest_api_framework_alpha-0.3.10}/framework/utils/encrypt.py
RENAMED
|
File without changes
|
{pytest_api_framework_alpha-0.3.8 → pytest_api_framework_alpha-0.3.10}/framework/utils/log_util.py
RENAMED
|
File without changes
|
{pytest_api_framework_alpha-0.3.8 → pytest_api_framework_alpha-0.3.10}/framework/utils/mock_util.py
RENAMED
|
File without changes
|
{pytest_api_framework_alpha-0.3.8 → pytest_api_framework_alpha-0.3.10}/framework/utils/yaml_util.py
RENAMED
|
File without changes
|
{pytest_api_framework_alpha-0.3.8 → pytest_api_framework_alpha-0.3.10}/framework/validate.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|