api-engine-xin 0.0.4__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.
@@ -0,0 +1,219 @@
1
+ import re
2
+ import requests
3
+ from jsonpath import jsonpath
4
+ from . import global_func
5
+ from .caseLog import CaseLogHandler
6
+ from .dbClient import DBClient
7
+ # 定义脚本中的全局变量
8
+ ENV = {}
9
+ db = DBClient()
10
+
11
+ class BaseCase(CaseLogHandler):
12
+ """用例执行基本父类"""
13
+
14
+ def __run_script(self, data):
15
+ # 执行前后置脚本,可以在前后置脚本中共享数据
16
+ test = self
17
+ global_var = ENV.get("envs")
18
+ print = self.print_log
19
+ # 定义脚本中的临时变量
20
+ self.env = {}
21
+ # 1、读取前置脚本数据
22
+ setup_scripts = data.get("setup_scripts")
23
+ # 2、执行字符串中有效的python代码
24
+ exec(setup_scripts)
25
+
26
+ response = yield
27
+
28
+ # 1、读取后置脚本数据
29
+ teardown_scripts = data.get("teardown_scripts")
30
+ # 2、执行字符串中有效的python代码
31
+ exec(teardown_scripts)
32
+
33
+ yield
34
+
35
+ def __setup_script(self, data):
36
+ """前置脚本处理"""
37
+ self.script_hook = self.__run_script(data)
38
+ next(self.script_hook)
39
+
40
+ def __teardown_script(self, data, response):
41
+ """后置脚本处理"""
42
+ self.script_hook.send(response)
43
+ """删除生成器对象"""
44
+ delattr(self, "script_hook")
45
+
46
+ def replace_data(self, data):
47
+ """替换测试用例中的变量数据"""
48
+ # 1、定义替换数据的规则
49
+ pattern = r"\${(.+?)}"
50
+ # 2、讲测试用例数据转换为字符串格式
51
+ data = str(data)
52
+ # 3、替换测试用例中的数据
53
+ while re.search(pattern, data):
54
+ # 获取匹配的数据内容
55
+ match_data = re.search(pattern, data)
56
+ key = match_data.group(1)
57
+ # 获取全局变量中的值
58
+ value = ENV.get("envs").get(key)
59
+ # 替换数据
60
+ data = data.replace(match_data.group(), str(value))
61
+ return eval(data)
62
+
63
+ def __handle_request_data(self, data):
64
+ """处理请求数据"""
65
+ self.name = data.get("name")
66
+ request_data = {}
67
+ # 1、处理请求url
68
+ if data.get("interface").get("url").startswith("http"):
69
+ request_data["url"] = data.get("interface").get("url")
70
+ else:
71
+ request_data["url"] = ENV.get("base_url") + data.get("interface").get("url")
72
+ request_data["method"] = data.get("interface").get("method")
73
+ # 2、处理请求头
74
+ request_data["headers"] = ENV.get("headers")
75
+ request_data["headers"].update(data.get("headers"))
76
+ # 3、处理请求参数
77
+ request_data["params"] = data.get("request_data").get("params")
78
+ if "application/json" in request_data["headers"].get("Content-Type"):
79
+ request_data["json"] = data.get("request_data").get("json")
80
+ elif "application/x-www-form-urlencoded" in request_data["headers"].get("Content-Type"):
81
+ request_data["data"] = data.get("request_data").get("data")
82
+ elif "multipart/form-data" in request_data["headers"].get("Content-Type"):
83
+ request_data["files"] = data.get("request_data").get("files")
84
+ # 4、替换请求中的变量名 为 具体的变量数据
85
+ request_data = self.replace_data(request_data)
86
+ self.url = request_data["url"]
87
+ self.method = request_data["method"]
88
+ self.request_headers = request_data["headers"]
89
+ return request_data
90
+
91
+ def __send_request(self, data):
92
+ """发送请求"""
93
+ request_data = self.__handle_request_data(data)
94
+ self.info_log(request_data)
95
+ response = requests.request(method=request_data.get("method"),
96
+ url=request_data.get("url"),
97
+ headers=request_data.get("headers"),
98
+ params=request_data.get("params"),
99
+ data=request_data.get("data"),
100
+ json=request_data.get("json"),
101
+ files=request_data.get("files"))
102
+ # 获取用例执行的请求和响应信息
103
+ self.request_body = response.request.body
104
+ self.status_code = response.status_code
105
+ self.response_headers = response.headers
106
+ self.response_body = response.text
107
+ self.info_log("请求地址:", self.url)
108
+ self.info_log("请求方法:", self.method)
109
+ self.info_log("请求头:", self.request_headers)
110
+ self.info_log("响应头:", self.response_headers)
111
+ self.info_log("请求体:", self.request_body)
112
+ self.info_log("响应体:", self.response_body)
113
+ return response
114
+
115
+ def perform(self, data):
116
+ """执行用例"""
117
+ self.__setup_script(data)
118
+ response = self.__send_request(data)
119
+ self.__teardown_script(data, response)
120
+
121
+ def save_env_variable(self, key, value):
122
+ """保存测试运行环境变量"""
123
+ self.info_log(f"保存(临时)环境变量:{key} = {value}")
124
+ self.env[key] = value
125
+
126
+ def del_evn_variable(self, key):
127
+ """删除测试运行环境变量"""
128
+ self.info_log(f"删除(临时)环境变量:{key}")
129
+ del self.env[key]
130
+
131
+ def save_global_variable(self, key, value):
132
+ """保存测试运行环境的全局变量"""
133
+ self.info_log(f"保存全局变量:{key} = {value}")
134
+ ENV.get("envs")[key] = value
135
+
136
+ def del_global_variable(self, key):
137
+ """删除测试运行环境的全局变量"""
138
+ self.info_log(f"删除全局变量:{key}")
139
+ del ENV.get("envs")[key]
140
+
141
+ def json_extract(self,obj,ext):
142
+ """通过jsonpath提取一个json数据"""
143
+ self.info_log("----通过jsonpath提取单个数据---")
144
+ res = jsonpath(obj, ext)
145
+ value = res[0] if res else ""
146
+ return value
147
+
148
+ def json_extract_list(self,obj,ext):
149
+ """通过jsonpath提取一组json数据"""
150
+ self.info_log("----通过jsonpath提取一组数据---")
151
+ res = jsonpath(obj, ext)
152
+ value = res if res else []
153
+ return value
154
+
155
+ def re_extract(self,obj,ext):
156
+ """
157
+ 通过正则提取一个数据
158
+ obj: 响应的json数据
159
+ ext: 匹配的正则表达式
160
+ """
161
+ self.info_log("----通过正则提取数据---")
162
+ # 1、判断响应是否为字符串
163
+ if not isinstance(obj,str):
164
+ obj = str(obj)
165
+ # 2、提取匹配正则表达式的第一个数据
166
+ res = re.search(ext,obj)
167
+ value = res.group(1) if res else ""
168
+ return value
169
+
170
+ def re_extract_list(self,obj,ext):
171
+ """
172
+ 通过正则提取一组数据
173
+ obj: 响应的json数据
174
+ ext: 匹配的正则表达式
175
+ """
176
+ self.info_log("----通过正则提取一组数据---")
177
+ # 1、判断响应是否为字符串
178
+ if not isinstance(obj,str):
179
+ obj = str(obj)
180
+ # 2、提取匹配正则表达式的所有数据
181
+ res = re.findall(ext,obj)
182
+ value = res if res else []
183
+ return value
184
+
185
+ def assertion(self,method,expect,actual):
186
+ """
187
+ :param method: 断言比较的方式
188
+ :param expect: 断言的期望结果
189
+ :param actual: 断言的实际结果
190
+ :return:
191
+ """
192
+ # 1、断言的方法
193
+ method_map = {
194
+ "相等": lambda a,b: a == b,
195
+ "相等忽略大小写": lambda a, b: a.lower() == b.lower(),
196
+ "不相等": lambda a,b: a != b,
197
+ "包含": lambda a,b: a in b,
198
+ "不包含": lambda a,b: a not in b,
199
+ "大于": lambda a,b: a > b,
200
+ "小于": lambda a,b: a < b,
201
+ "大于等于": lambda a,b: a >= b,
202
+ "小于等于": lambda a,b: a <= b,
203
+ "正则匹配": lambda a,b: re.search(a,b)
204
+ }
205
+ # 2、断言操作
206
+ assert_fun = method_map.get(method)
207
+ if assert_fun is None:
208
+ raise Exception("不支持的断言方法")
209
+ else:
210
+ self.debug_log(f"断言比较方法是:{method}")
211
+ self.debug_log(f"预期结果是:{expect}")
212
+ self.debug_log(f"实际结果是:{actual}")
213
+ try:
214
+ assert assert_fun(expect,actual)
215
+ except AssertionError:
216
+ self.error_log(f"断言失败,实际结果({actual}) 不满足({method}) 期望结果({expect})")
217
+ raise AssertionError(f"断言失败,实际结果({actual}) 不满足({method}) 期望结果({expect})")
218
+ else:
219
+ self.info_log(f"断言成功,实际结果({actual}) 满足({method}) 期望结果({expect})")
@@ -0,0 +1,3 @@
1
+ from ApiEngine.caseLog import CaseLogHandler
2
+
3
+ log = CaseLogHandler()
@@ -0,0 +1,40 @@
1
+ class CaseLogHandler:
2
+ """用例日志处理类"""
3
+ def save_log(self,msg,level):
4
+ """保存日志"""
5
+ # 1、判断当前实例是否有日志属性
6
+ if not hasattr(self,"log_data"):
7
+ setattr(self,"log_data",[])
8
+ # 2、将日志数据保存到属性中
9
+ getattr(self,"log_data").append((level,msg))
10
+ print((level,msg))
11
+
12
+ def print_log(self,*args):
13
+ """记录debug日志"""
14
+ msg = " ".join([str(i) for i in args])
15
+ self.save_log(msg,"PRINT")
16
+
17
+ def debug_log(self,*args):
18
+ """记录debug日志"""
19
+ msg = " ".join([str(i) for i in args])
20
+ self.save_log(msg,"DEBUG")
21
+
22
+ def info_log(self,*args):
23
+ """记录info日志"""
24
+ msg = " ".join([str(i) for i in args])
25
+ self.save_log(msg,"INFO")
26
+
27
+ def warning_log(self,*args):
28
+ """记录warning日志"""
29
+ msg = " ".join([str(i) for i in args])
30
+ self.save_log(msg,"WARNING")
31
+
32
+ def error_log(self,*args):
33
+ """记录error日志"""
34
+ msg = " ".join([str(i) for i in args])
35
+ self.save_log(msg,"ERROR")
36
+
37
+ def critical_log(self,*args):
38
+ """记录critical日志"""
39
+ msg = " ".join([str(i) for i in args])
40
+ self.save_log(msg,"CRITICAL")
@@ -0,0 +1,174 @@
1
+ from ApiEngine import global_func,log
2
+ from ApiEngine.BaseCase import BaseCase, db, ENV
3
+ from ApiEngine.testResult import TestResult
4
+
5
+
6
+ class TestRunner:
7
+ def __init__(self, cases, env_data):
8
+ """
9
+ :param cases: 要执行的测试数据
10
+ :param env_data: 执行测试时的环境数据
11
+ """
12
+ self.cases = cases
13
+ self.env_data = env_data
14
+ self.result = []
15
+
16
+ def run(self):
17
+ """执行测试用例的方法"""
18
+ # 根据数据库的配置初始化数据库的连接
19
+ db.init_connent(test_env_data.pop("db"))
20
+ # 遍历所有测试用例
21
+ for items in self.cases:
22
+ log.info_log("执行测试套件:",items["name"])
23
+ # 将全局环境测试加载到ENV中
24
+ ENV.clear()
25
+ ENV.update(test_env_data)
26
+ # 将tools中的函数(用户自定义),通过exec执行(字符串中的python函数),加载到TestTools模块的命名空间中
27
+ exec(ENV.get("global_func"), global_func.__dict__)
28
+ # 创建测试结果的记录器
29
+ test_result = TestResult(all=len(items["cases"]),name=items["name"])
30
+ # 运行测试用例
31
+ for case in items["cases"]:
32
+ self.perform_case(case,test_result)
33
+ # 获取测试结果执行记录器中的结果
34
+ res = test_result.get_result_info()
35
+ self.result.append(res)
36
+ # 断开数据库连接
37
+ db.close_db_connent()
38
+ # 返回用例执行结果
39
+ return self.result
40
+
41
+ def perform_case(self, case,test_result):
42
+ # 运行测试用例
43
+ c=BaseCase()
44
+ try:
45
+ c.perform(case)
46
+ except AssertionError as e:
47
+ test_result.add_fail(c)
48
+ except Exception as e:
49
+ test_result.add_error(c,e)
50
+ else:
51
+ test_result.add_success(c)
52
+
53
+ if __name__ == '__main__':
54
+ test_suites = [
55
+ {
56
+ "name":"测试套件1",
57
+ "cases":[
58
+ {
59
+ "name": "登录接口",
60
+ "interface": {
61
+ "url": "/member/public/login",
62
+ "method": "post"
63
+ },
64
+ "headers": {
65
+ "Content-Type": "application/x-www-form-urlencoded",
66
+ "Token": "${token}"
67
+ },
68
+ "request_data": {
69
+ "params": {},
70
+ "data": {"keywords": "13012349900", "password": "test123", "user2": "${username}",
71
+ "pwd2": "${password}", "mobile": "${mobile}"},
72
+ "json": {"keywords": "13012349900", "password": "test123", "user2": "${username}",
73
+ "pwd2": "${password}", "mobile": "${mobile}"}
74
+ },
75
+ "setup_scripts": open("..\\tests\\setup_scripts.txt", "r", encoding="utf-8").read(),
76
+ "teardown_scripts": open("..\\tests\\teardown_scripts.txt", "r", encoding="utf-8").read()
77
+ },
78
+ {
79
+ "name": "登录接口2",
80
+ "interface": {
81
+ "url": "/member/public/login",
82
+ "method": "post"
83
+ },
84
+ "headers": {
85
+ "Content-Type": "application/x-www-form-urlencoded",
86
+ "Token": "${token}"
87
+ },
88
+ "request_data": {
89
+ "params": {},
90
+ "data": {"keywords": "13012349900", "password": "test123", "user2": "${username}",
91
+ "pwd2": "${password}", "mobile": "${mobile}"},
92
+ "json": {"keywords": "13012349900", "password": "test123", "user2": "${username}",
93
+ "pwd2": "${password}", "mobile": "${mobile}"}
94
+ },
95
+ "setup_scripts": open("..\\tests\\setup_scripts.txt", "r", encoding="utf-8").read(),
96
+ "teardown_scripts": ""
97
+ }
98
+ ]
99
+ },
100
+ {
101
+ "name": "测试套件2",
102
+ "cases": [
103
+ {
104
+ "name": "登录接口3",
105
+ "interface": {
106
+ "url": "/member/public/login",
107
+ "method": "post"
108
+ },
109
+ "headers": {
110
+ "Content-Type": "application/x-www-form-urlencoded",
111
+ "Token": "${token}"
112
+ },
113
+ "request_data": {
114
+ "params": {},
115
+ "data": {"keywords": "13012349900", "password": "test123", "user2": "${username}",
116
+ "pwd2": "${password}", "mobile": "${mobile}"},
117
+ "json": {"keywords": "13012349900", "password": "test123", "user2": "${username}",
118
+ "pwd2": "${password}", "mobile": "${mobile}"}
119
+ },
120
+ "setup_scripts": open("..\\tests\\setup_scripts.txt", "r", encoding="utf-8").read(),
121
+ "teardown_scripts": open("..\\tests\\teardown_scripts.txt", "r", encoding="utf-8").read()
122
+ },
123
+ {
124
+ "name": "登录接口4",
125
+ "interface": {
126
+ "url": "/member/public/login",
127
+ "method": "post"
128
+ },
129
+ "headers": {
130
+ "Content-Type": "application/x-www-form-urlencoded",
131
+ "Token": "${token}"
132
+ },
133
+ "request_data": {
134
+ "params": {},
135
+ "data": {"keywords": "13012349900", "password": "test123", "user2": "${username}",
136
+ "pwd2": "${password}", "mobile": "${mobile}"},
137
+ "json": {"keywords": "13012349900", "password": "test123", "user2": "${username}",
138
+ "pwd2": "${password}", "mobile": "${mobile}"}
139
+ },
140
+ "setup_scripts": open("..\\tests\\setup_scripts.txt", "r", encoding="utf-8").read(),
141
+ "teardown_scripts": ""
142
+ }
143
+ ]
144
+ }
145
+ ]
146
+ # 全局环境数据
147
+ test_env_data = {
148
+ "base_url": "http://121.43.169.97:8081",
149
+ "headers": {
150
+ "Content-Type": "application/json"
151
+ },
152
+ # 环境变量
153
+ "envs": {
154
+ "username": "rand_13012349900",
155
+ "password": "rand_test123",
156
+ "token": "12345678"
157
+ },
158
+ "global_func": open("..\\tests\\Tools.py", "r", encoding="utf-8").read(),
159
+ "db": [
160
+ {
161
+ "name": "P2P",
162
+ "type": "mysql",
163
+ "config": {
164
+ "host": "121.43.169.97",
165
+ "port": 3306,
166
+ "user": "student",
167
+ "password": "P2P_student_2023"
168
+ }
169
+ }
170
+ ]
171
+ }
172
+ runner = TestRunner(test_suites, test_env_data)
173
+ result = runner.run()
174
+ log.info_log("测试结果:", result)
@@ -0,0 +1,92 @@
1
+ import pymysql,pymssql
2
+
3
+ class DBBase:
4
+ """数据库操作类"""
5
+ conn = None
6
+ cursor = None
7
+
8
+ def execute_sql(self, sql, params=None):
9
+ """执行sql语句,并返回单条数据"""
10
+ try:
11
+ self.cursor.execute(sql, params)
12
+ return self.cursor.fetchone()
13
+ except Exception as e:
14
+ raise e
15
+
16
+ def execute_all(self,sql, params=None):
17
+ """执行sql语句,并返回所有数据"""
18
+ try:
19
+ self.cursor.execute(sql, params)
20
+ return self.cursor.fetchall()
21
+ except Exception as e:
22
+ raise e
23
+
24
+ def close_db(self):
25
+ """关闭数据库连接"""
26
+ self.cursor.close()
27
+ self.conn.close()
28
+
29
+ class MysqlDb(DBBase):
30
+ def __init__(self,db_config):
31
+ """mysql数据库连接"""
32
+ self.conn = pymysql.connect(**db_config,autocommit=True)
33
+ self.cursor = self.conn.cursor(pymysql.cursors.DictCursor)
34
+
35
+ class SqlServerDb(DBBase):
36
+ def __init__(self,db_config):
37
+ """sqlserver数据库连接"""
38
+ self.conn = pymssql.connect(**db_config,autocommit=True)
39
+ self.cursor = self.conn.cursor(as_dict=True)
40
+
41
+ # class OracleDb(DBBase):
42
+ # """mysql数据库操作类"""
43
+ # def __init__(self,db_config):
44
+ # # 连接数据库
45
+ # self.conn = cx_Oracle.connect(**db_config)
46
+ # self.cursor = self.conn.cursor()
47
+
48
+ class DBClient:
49
+ """数据库连接工具"""
50
+ def init_connent(self,dbs):
51
+ if isinstance(dbs,dict):
52
+ self.create_db_connect(dbs)
53
+ elif isinstance(dbs,list):
54
+ for db in dbs:
55
+ self.create_db_connect(db)
56
+ else:
57
+ raise Exception("数据库格式配置错误")
58
+
59
+ def create_db_connect(self,dbs):
60
+ """创建数据库连接"""
61
+ # 1、如果配置不正确,则抛出异常
62
+ if not (dbs.get("name") and dbs.get("type") and dbs.get("config")):
63
+ raise Exception("数据库配置错误")
64
+ if dbs.get("type") == "mysql":
65
+ setattr(self,dbs.get("name"),MysqlDb(dbs.get("config")))
66
+ elif dbs.get("type") == "sqlserver":
67
+ setattr(self, dbs.get("name"), SqlServerDb(dbs.get("config")))
68
+ else:
69
+ raise Exception("不支持的数据库类型")
70
+
71
+ def close_db_connent(self):
72
+ """关闭数据库连接"""
73
+ for db in self.__dict__:
74
+ if isinstance(getattr(self,db),DBBase):
75
+ getattr(self,db).close_db()
76
+
77
+ if __name__ == '__main__':
78
+ items = [
79
+ {
80
+ "name": "P2P",
81
+ "type": "mysql",
82
+ "config": {
83
+ "host": "121.43.169.97",
84
+ "port": 3306,
85
+ "user": "student",
86
+ "password": "P2P_student_2023"
87
+ }
88
+ }
89
+ ]
90
+ db = DBClient()
91
+ db.init_connent(items)
92
+ print(db.P2P.execute_sql("SELECT * FROM czbk_member.mb_member;"))
File without changes
@@ -0,0 +1,99 @@
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, "response_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
+ }
37
+ self.results.append(info)
38
+
39
+ def add_fail(self, test: BaseCase):
40
+ """
41
+ :param test: 用例对象
42
+ :return:
43
+ """
44
+ self.fail += 1
45
+ info = {
46
+ "name": getattr(test, "name",""),
47
+ "url": getattr(test, "url",""),
48
+ "method": getattr(test, "method",""),
49
+ "request_headers": getattr(test, "request_headers",""),
50
+ "request_body": getattr(test, "request_body",""),
51
+ "response_code": getattr(test, "response_code",""),
52
+ "response_headers": getattr(test, "response_headers",""),
53
+ "response_body": getattr(test, "response_body",""),
54
+ "status": "fail",
55
+ "log_data": getattr(test, "log_data", "")
56
+ }
57
+ self.results.append(info)
58
+
59
+ def add_error(self, test: BaseCase, error):
60
+ """
61
+ :param test: 用例对象
62
+ :return:
63
+ """
64
+ self.error += 1
65
+ log.error_log("用例执行错误,错误信息信息:", error)
66
+ info = {
67
+ "name": getattr(test, "name",""),
68
+ "url": getattr(test, "url",""),
69
+ "method": getattr(test, "method",""),
70
+ "request_headers": getattr(test, "request_headers",""),
71
+ "request_body": getattr(test, "request_body",""),
72
+ "response_code": getattr(test, "response_code",""),
73
+ "response_headers": getattr(test, "response_headers",""),
74
+ "response_body": getattr(test, "response_body",""),
75
+ "status": "error",
76
+ "log_data": getattr(test, "log_data", "")
77
+ }
78
+ self.results.append(info)
79
+
80
+ def get_result_info(self):
81
+ """
82
+ :return: 测试结果信息
83
+ """
84
+ if self.success == self.all:
85
+ state = "success"
86
+ elif self.fail > 0:
87
+ state = "fail"
88
+ else:
89
+ state = "error"
90
+ info = {
91
+ "name": self.name,
92
+ "all": self.all,
93
+ "success": self.success,
94
+ "fail": self.fail,
95
+ "error": self.error,
96
+ "results": self.results,
97
+ "state": state
98
+ }
99
+ return info
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) [年份] [版权所有者姓名/组织名]
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,37 @@
1
+ Metadata-Version: 2.4
2
+ Name: api_engine_xin
3
+ Version: 0.0.4
4
+ Summary: 接口测试平台测试用例执行引擎
5
+ Home-page: https://pypi.org/project/api_engine_xin/
6
+ Author: Shawn
7
+ Author-email: xiaoh0525@xiaoh.com
8
+ Keywords: python,apitest,apiEngine
9
+ Classifier: Development Status :: 3 - Alpha
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3.6
13
+ Classifier: Programming Language :: Python :: 3.7
14
+ Classifier: Programming Language :: Python :: 3.8
15
+ Classifier: Programming Language :: Python :: 3.9
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: License :: OSI Approved :: MIT License
18
+ Classifier: Operating System :: OS Independent
19
+ Requires-Python: >=3.6
20
+ Description-Content-Type: text/markdown
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
+
36
+
37
+ readme.md
@@ -0,0 +1 @@
1
+ readme.md
@@ -0,0 +1,37 @@
1
+ Metadata-Version: 2.4
2
+ Name: api_engine_xin
3
+ Version: 0.0.4
4
+ Summary: 接口测试平台测试用例执行引擎
5
+ Home-page: https://pypi.org/project/api_engine_xin/
6
+ Author: Shawn
7
+ Author-email: xiaoh0525@xiaoh.com
8
+ Keywords: python,apitest,apiEngine
9
+ Classifier: Development Status :: 3 - Alpha
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3.6
13
+ Classifier: Programming Language :: Python :: 3.7
14
+ Classifier: Programming Language :: Python :: 3.8
15
+ Classifier: Programming Language :: Python :: 3.9
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: License :: OSI Approved :: MIT License
18
+ Classifier: Operating System :: OS Independent
19
+ Requires-Python: >=3.6
20
+ Description-Content-Type: text/markdown
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
+
36
+
37
+ readme.md
@@ -0,0 +1,15 @@
1
+ LICENSE
2
+ README.md
3
+ setup.py
4
+ ApiEngine/BaseCase.py
5
+ ApiEngine/__init__.py
6
+ ApiEngine/caseLog.py
7
+ ApiEngine/core.py
8
+ ApiEngine/dbClient.py
9
+ ApiEngine/global_func.py
10
+ ApiEngine/testResult.py
11
+ api_engine_xin.egg-info/PKG-INFO
12
+ api_engine_xin.egg-info/SOURCES.txt
13
+ api_engine_xin.egg-info/dependency_links.txt
14
+ api_engine_xin.egg-info/requires.txt
15
+ api_engine_xin.egg-info/top_level.txt
@@ -0,0 +1,2 @@
1
+ pymysql>=1.0.0
2
+ requests>=2.26.0
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,38 @@
1
+ from setuptools import setup, find_packages
2
+ import codecs
3
+ import os
4
+
5
+ # 获取当前项目根目录
6
+ here = os.path.abspath(os.path.dirname(__file__))
7
+
8
+ # 读取README.md作为项目长描述(可选)
9
+ with codecs.open(os.path.join(here, "README.md"), encoding="utf-8") as fh:
10
+ long_description = "\n" + fh.read()
11
+
12
+ # 核心配置
13
+ setup(
14
+ name="api_engine_xin", # ✅【必须改】pip install 这个名字!全网唯一,不能和PyPI上已有的包名重复
15
+ version="0.0.4", # ✅【必须改】版本号,每次更新包都要升级版本(如0.0.2、0.1.0)
16
+ author="Shawn",# ✅【必须改】你的名字/昵称
17
+ author_email="xiaoh0525@xiaoh.com",# ✅【必须改】你的注册PyPI的邮箱
18
+ description="接口测试平台测试用例执行引擎", # ✅【必须改】一句话说明你的包是干嘛的
19
+ long_description=long_description,
20
+ long_description_content_type="text/markdown",
21
+ url="https://pypi.org/project/api_engine_xin/", # 可选,比如你的github/gitee地址,没有就写你的PyPI包地址
22
+ packages=find_packages(), # 自动识别你的包目录下的所有py文件,不用手动写
23
+ python_requires=">=3.6", # 支持的Python版本,建议写3.6+,兼容大部分环境
24
+ install_requires=["pymysql>=1.0.0", "requests>=2.26.0"], # ✅【按需改】你的包依赖的第三方库,例如["redis>=4.0.0", "pymysql>=1.0.0"],无依赖则留空列表
25
+ keywords=["python", "apitest", "apiEngine"], # 可选,方便别人搜索你的包
26
+ classifiers=[
27
+ "Development Status :: 3 - Alpha",
28
+ "Intended Audience :: Developers",
29
+ "Programming Language :: Python :: 3",
30
+ "Programming Language :: Python :: 3.6",
31
+ "Programming Language :: Python :: 3.7",
32
+ "Programming Language :: Python :: 3.8",
33
+ "Programming Language :: Python :: 3.9",
34
+ "Programming Language :: Python :: 3.10",
35
+ "License :: OSI Approved :: MIT License",
36
+ "Operating System :: OS Independent",
37
+ ],
38
+ )