har2pytest 1.0.0__py3-none-any.whl
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.
- har2pytest/__init__.py +36 -0
- har2pytest/__main__.py +294 -0
- har2pytest/api_generator.py +601 -0
- har2pytest/config.py +256 -0
- har2pytest/har_generator.py +66 -0
- har2pytest/har_parser.py +280 -0
- har2pytest/logger.py +29 -0
- har2pytest/swagger_handler.py +540 -0
- har2pytest/testcase_generator.py +1225 -0
- har2pytest/url_matcher.py +324 -0
- har2pytest/utils.py +324 -0
- har2pytest-1.0.0.dist-info/METADATA +104 -0
- har2pytest-1.0.0.dist-info/RECORD +17 -0
- har2pytest-1.0.0.dist-info/WHEEL +5 -0
- har2pytest-1.0.0.dist-info/entry_points.txt +2 -0
- har2pytest-1.0.0.dist-info/licenses/LICENSE +21 -0
- har2pytest-1.0.0.dist-info/top_level.txt +1 -0
har2pytest/__init__.py
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"""
|
|
2
|
+
API工具包 - 用于从HAR文件生成API接口和测试用例
|
|
3
|
+
|
|
4
|
+
主要功能:
|
|
5
|
+
1. HAR文件解析
|
|
6
|
+
2. API文件生成
|
|
7
|
+
3. 测试用例生成
|
|
8
|
+
4. Swagger文档更新
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from .api_generator import APIGenerator
|
|
12
|
+
from .config import APIConfig
|
|
13
|
+
from .har_parser import HARParser
|
|
14
|
+
from .logger import get_logger, logger
|
|
15
|
+
from .swagger_handler import SwaggerHandler
|
|
16
|
+
from .testcase_generator import TestCaseGenerator
|
|
17
|
+
from .utils import (
|
|
18
|
+
format_headers_for_python,
|
|
19
|
+
format_parameter_value,
|
|
20
|
+
format_params_for_python,
|
|
21
|
+
parse_api_file,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
__all__ = [
|
|
25
|
+
"APIConfig",
|
|
26
|
+
"HARParser",
|
|
27
|
+
"APIGenerator",
|
|
28
|
+
"TestCaseGenerator",
|
|
29
|
+
"SwaggerHandler",
|
|
30
|
+
"get_logger",
|
|
31
|
+
"logger",
|
|
32
|
+
"parse_api_file",
|
|
33
|
+
"format_parameter_value",
|
|
34
|
+
"format_headers_for_python",
|
|
35
|
+
"format_params_for_python",
|
|
36
|
+
]
|
har2pytest/__main__.py
ADDED
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
"""
|
|
2
|
+
har2pytest 命令行入口
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
import asyncio
|
|
7
|
+
|
|
8
|
+
from .api_generator import APIGenerator
|
|
9
|
+
from .config import APIConfig
|
|
10
|
+
from .har_generator import generate_api_files_from_har
|
|
11
|
+
from .har_parser import HARParser
|
|
12
|
+
from .logger import logger
|
|
13
|
+
from .swagger_handler import SwaggerHandler
|
|
14
|
+
from .testcase_generator import TestCaseGenerator
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def main():
|
|
18
|
+
"""
|
|
19
|
+
主函数 - 支持多种命令行操作模式
|
|
20
|
+
"""
|
|
21
|
+
# 初始化配置(通过 get_config 触发,会自动缓存)
|
|
22
|
+
APIConfig.get_config("BASE_URLS")
|
|
23
|
+
|
|
24
|
+
# 创建主解析器
|
|
25
|
+
parser = argparse.ArgumentParser(
|
|
26
|
+
prog="har2pytest",
|
|
27
|
+
description="har2pytest - HAR文件转pytest测试用例工具",
|
|
28
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
29
|
+
epilog="""示例用法:
|
|
30
|
+
# 从HAR文件生成API接口文件
|
|
31
|
+
har2pytest api api_request.har --output apis
|
|
32
|
+
|
|
33
|
+
# 从Swagger文档生成API接口文件
|
|
34
|
+
har2pytest swagger https://petstore.swagger.io/v2/api-docs
|
|
35
|
+
|
|
36
|
+
# 查看HAR文件摘要
|
|
37
|
+
har2pytest summary api_request.har
|
|
38
|
+
|
|
39
|
+
# 生成参数化测试用例
|
|
40
|
+
har2pytest testcase api_request.har --pattern list_query --mark test_4291
|
|
41
|
+
|
|
42
|
+
# 生成复杂场景测试用例
|
|
43
|
+
har2pytest testcase api_request.har --pattern complex_scenario --url /api/user/login --mark test_4295
|
|
44
|
+
|
|
45
|
+
# 批量生成测试用例
|
|
46
|
+
har2pytest testcase --pattern batch --api-files apis/mall_mobile_application --mark test_4295
|
|
47
|
+
""",
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
# 创建子命令解析器
|
|
51
|
+
subparsers = parser.add_subparsers(dest="command", help="可用命令")
|
|
52
|
+
|
|
53
|
+
# api 子命令
|
|
54
|
+
api_parser = subparsers.add_parser("api", help="从HAR文件生成API接口文件", description="从HAR文件生成API接口文件")
|
|
55
|
+
api_parser.add_argument("har_file", nargs="?", default="api_request.har", help="HAR文件路径")
|
|
56
|
+
api_parser.add_argument("--output", "-o", default=APIConfig.DEFAULT_API_DIR(), help="输出目录")
|
|
57
|
+
api_parser.add_argument("--overwrite", "-f", action="store_true", help="强制覆盖现有文件")
|
|
58
|
+
|
|
59
|
+
# summary 子命令
|
|
60
|
+
sum_parser = subparsers.add_parser(
|
|
61
|
+
"summary", help="显示HAR文件的API请求摘要", description="显示HAR文件的API请求摘要"
|
|
62
|
+
)
|
|
63
|
+
sum_parser.add_argument("har_file", help="HAR文件路径")
|
|
64
|
+
|
|
65
|
+
# testcase 子命令
|
|
66
|
+
tc_parser = subparsers.add_parser(
|
|
67
|
+
"testcase",
|
|
68
|
+
help="生成测试用例",
|
|
69
|
+
description="从HAR文件生成pytest测试用例",
|
|
70
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
71
|
+
epilog="""示例用法:
|
|
72
|
+
# 生成查询类参数化测试用例(不传mark)
|
|
73
|
+
har2pytest testcase api_request.har --pattern list_query
|
|
74
|
+
|
|
75
|
+
# 生成查询类参数化测试用例(传mark)
|
|
76
|
+
har2pytest testcase api_request.har --pattern list_query --mark test_4291
|
|
77
|
+
|
|
78
|
+
# 生成复杂场景测试用例(不传mark)
|
|
79
|
+
har2pytest testcase api_request.har --pattern complex_scenario --url /api/user/login
|
|
80
|
+
|
|
81
|
+
# 生成复杂场景测试用例(传mark)
|
|
82
|
+
har2pytest testcase api_request.har --pattern complex_scenario --url /api/user/login --mark test_4295
|
|
83
|
+
""",
|
|
84
|
+
)
|
|
85
|
+
tc_parser.add_argument("har_file", nargs="?", default=None, help="HAR文件路径(batch模式不需要)")
|
|
86
|
+
tc_parser.add_argument(
|
|
87
|
+
"--pattern",
|
|
88
|
+
default="list_query",
|
|
89
|
+
choices=["list_query", "complex_scenario", "batch"],
|
|
90
|
+
help="测试用例模式: list_query(查询类参数化)、complex_scenario(复杂场景) 或 batch(批量生成)",
|
|
91
|
+
)
|
|
92
|
+
tc_parser.add_argument("--mark", "-m", help="测试标记(如 test_4291)")
|
|
93
|
+
tc_parser.add_argument("--url", "-u", help="目标接口URL(可选,指定后只生成该接口的测试用例)")
|
|
94
|
+
tc_parser.add_argument("--output", "-o", default="testcases", help="输出目录")
|
|
95
|
+
tc_parser.add_argument("--api-dir", default="apis", help="API文件目录")
|
|
96
|
+
tc_parser.add_argument("--api-files", help="指定API文件集合(batch模式使用,多个文件用逗号分隔)")
|
|
97
|
+
|
|
98
|
+
# swagger 子命令
|
|
99
|
+
swagger_parser = subparsers.add_parser(
|
|
100
|
+
"swagger",
|
|
101
|
+
help="从Swagger文档生成API接口文件",
|
|
102
|
+
description="从Swagger文档生成API接口文件",
|
|
103
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
104
|
+
epilog="""示例用法:
|
|
105
|
+
# 从Swagger文档生成所有API文件
|
|
106
|
+
har2pytest swagger https://petstore.swagger.io/v2/api-docs
|
|
107
|
+
|
|
108
|
+
# 从Swagger文档生成API文件,指定输出目录
|
|
109
|
+
har2pytest swagger https://petstore.swagger.io/v2/api-docs --output apis
|
|
110
|
+
|
|
111
|
+
# 从Swagger文档生成API文件,强制覆盖
|
|
112
|
+
har2pytest swagger https://petstore.swagger.io/v2/api-docs --overwrite
|
|
113
|
+
|
|
114
|
+
# 从Swagger文档生成指定路径的API文件
|
|
115
|
+
har2pytest swagger https://petstore.swagger.io/v2/api-docs --path /pet/{petId}
|
|
116
|
+
""",
|
|
117
|
+
)
|
|
118
|
+
swagger_parser.add_argument("swagger_url", help="Swagger文档URL")
|
|
119
|
+
swagger_parser.add_argument("--output", "-o", default=APIConfig.DEFAULT_API_DIR(), help="输出目录")
|
|
120
|
+
swagger_parser.add_argument("--overwrite", "-f", action="store_true", help="强制覆盖现有文件")
|
|
121
|
+
swagger_parser.add_argument("--path", "-p", help="只生成指定的API路径(如 /pet/{petId})")
|
|
122
|
+
|
|
123
|
+
# 解析参数
|
|
124
|
+
args = parser.parse_args()
|
|
125
|
+
|
|
126
|
+
# 如果没有指定命令,默认使用 api 命令
|
|
127
|
+
if args.command is None:
|
|
128
|
+
args.command = "api"
|
|
129
|
+
|
|
130
|
+
# 执行对应的命令
|
|
131
|
+
if args.command == "api":
|
|
132
|
+
asyncio.run(handle_api(args))
|
|
133
|
+
elif args.command == "summary":
|
|
134
|
+
handle_summary(args)
|
|
135
|
+
elif args.command == "testcase":
|
|
136
|
+
asyncio.run(handle_testcase(args))
|
|
137
|
+
elif args.command == "swagger":
|
|
138
|
+
asyncio.run(handle_swagger(args))
|
|
139
|
+
elif args.command == "help":
|
|
140
|
+
parser.print_help()
|
|
141
|
+
else:
|
|
142
|
+
logger.error(f"未知命令: {args.command}")
|
|
143
|
+
parser.print_help()
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
async def handle_api(args):
|
|
147
|
+
"""处理 api 命令"""
|
|
148
|
+
har_file = args.har_file
|
|
149
|
+
output_dir = args.output
|
|
150
|
+
force_overwrite = args.overwrite
|
|
151
|
+
|
|
152
|
+
logger.info(f"从HAR文件生成API接口文件: {har_file}")
|
|
153
|
+
logger.info(f"输出目录: {output_dir}")
|
|
154
|
+
logger.info(f"强制覆盖: {force_overwrite}")
|
|
155
|
+
logger.info("-" * 50)
|
|
156
|
+
|
|
157
|
+
api_generator = APIGenerator(output_dir)
|
|
158
|
+
generated_files = await generate_api_files_from_har(
|
|
159
|
+
har_file, force_overwrite=force_overwrite, api_generator=api_generator
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
logger.info("-" * 50)
|
|
163
|
+
logger.info(f"共生成 {len(generated_files)} 个API接口文件")
|
|
164
|
+
|
|
165
|
+
if generated_files:
|
|
166
|
+
api_generator.generate_index_file(generated_files)
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def handle_summary(args):
|
|
170
|
+
"""处理 summary 命令"""
|
|
171
|
+
har_file = args.har_file
|
|
172
|
+
|
|
173
|
+
parser = HARParser()
|
|
174
|
+
parser.print_api_summary(har_file)
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
async def handle_swagger(args):
|
|
178
|
+
"""处理 swagger 命令"""
|
|
179
|
+
swagger_url = args.swagger_url
|
|
180
|
+
output_dir = args.output
|
|
181
|
+
force_overwrite = args.overwrite
|
|
182
|
+
specific_path = args.path
|
|
183
|
+
|
|
184
|
+
logger.info(f"从Swagger文档生成API接口文件: {swagger_url}")
|
|
185
|
+
logger.info(f"输出目录: {output_dir}")
|
|
186
|
+
logger.info(f"强制覆盖: {force_overwrite}")
|
|
187
|
+
if specific_path:
|
|
188
|
+
logger.info(f"只生成指定路径: {specific_path}")
|
|
189
|
+
logger.info("-" * 50)
|
|
190
|
+
|
|
191
|
+
api_generator = APIGenerator(output_dir)
|
|
192
|
+
swagger_handler = SwaggerHandler(api_generator=api_generator)
|
|
193
|
+
generated_files = await swagger_handler.generate_apis_from_swagger(swagger_url, force_overwrite, specific_path)
|
|
194
|
+
|
|
195
|
+
logger.info("-" * 50)
|
|
196
|
+
logger.info(f"共生成 {len(generated_files)} 个API接口文件")
|
|
197
|
+
|
|
198
|
+
if generated_files:
|
|
199
|
+
api_generator.generate_index_file(generated_files)
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
async def handle_testcase(args):
|
|
203
|
+
"""处理 testcase 命令"""
|
|
204
|
+
har_file = args.har_file
|
|
205
|
+
pattern = args.pattern
|
|
206
|
+
task_id = args.mark
|
|
207
|
+
target_url = args.url
|
|
208
|
+
output_dir = args.output
|
|
209
|
+
api_dir = args.api_dir
|
|
210
|
+
|
|
211
|
+
if pattern == "list_query":
|
|
212
|
+
# 验证必填参数
|
|
213
|
+
if not har_file:
|
|
214
|
+
logger.error("错误: list_query 模式必须指定 HAR 文件")
|
|
215
|
+
logger.error("使用示例: har2pytest testcase api.har --pattern list_query --url /api/user/list")
|
|
216
|
+
return
|
|
217
|
+
if not target_url:
|
|
218
|
+
logger.error("错误: list_query 模式必须指定 --url 参数")
|
|
219
|
+
logger.error("使用示例: har2pytest testcase api.har --pattern list_query --url /api/user/list")
|
|
220
|
+
return
|
|
221
|
+
|
|
222
|
+
logger.info(f"生成查询类参数化测试用例: {har_file}")
|
|
223
|
+
logger.info(f"任务ID: {task_id}")
|
|
224
|
+
logger.info(f"目标接口: {target_url}")
|
|
225
|
+
logger.info("-" * 50)
|
|
226
|
+
|
|
227
|
+
generator = TestCaseGenerator(api_dir=api_dir, output_dir=output_dir)
|
|
228
|
+
test_files = generator.generate_parametrized_list_testcases(har_file, task_id, target_url)
|
|
229
|
+
|
|
230
|
+
logger.info("-" * 50)
|
|
231
|
+
if test_files:
|
|
232
|
+
logger.info(f"成功生成 {len(test_files)} 个测试用例文件:")
|
|
233
|
+
for test_file in test_files:
|
|
234
|
+
logger.info(f" - {test_file}")
|
|
235
|
+
else:
|
|
236
|
+
logger.info("生成测试用例文件失败")
|
|
237
|
+
|
|
238
|
+
elif pattern == "complex_scenario":
|
|
239
|
+
# 验证必填参数
|
|
240
|
+
if not har_file:
|
|
241
|
+
logger.error("错误: complex_scenario 模式必须指定 HAR 文件")
|
|
242
|
+
logger.error("使用示例: har2pytest testcase api.har --pattern complex_scenario --url /api/user/login")
|
|
243
|
+
return
|
|
244
|
+
if not target_url:
|
|
245
|
+
logger.error("错误: complex_scenario 模式必须指定 --url 参数")
|
|
246
|
+
logger.error("使用示例: har2pytest testcase api.har --pattern complex_scenario --url /api/user/login")
|
|
247
|
+
return
|
|
248
|
+
|
|
249
|
+
logger.info(f"生成复杂场景测试用例: {har_file}")
|
|
250
|
+
logger.info(f"任务ID: {task_id}")
|
|
251
|
+
logger.info(f"目标接口: {target_url}")
|
|
252
|
+
logger.info("-" * 50)
|
|
253
|
+
|
|
254
|
+
generator = TestCaseGenerator(api_dir=api_dir, output_dir=output_dir)
|
|
255
|
+
test_file = generator.generate_scenario_testcase(har_file, target_url, task_id)
|
|
256
|
+
|
|
257
|
+
logger.info("-" * 50)
|
|
258
|
+
if test_file:
|
|
259
|
+
logger.info(f"成功生成测试用例文件: {test_file.replace('\\', '/')}")
|
|
260
|
+
else:
|
|
261
|
+
logger.info("生成测试用例文件失败")
|
|
262
|
+
|
|
263
|
+
elif pattern == "batch":
|
|
264
|
+
# batch 模式:批量生成测试用例(直接从API文件读取参数)
|
|
265
|
+
api_files_arg = args.api_files
|
|
266
|
+
if not api_files_arg:
|
|
267
|
+
logger.error("错误: batch 模式必须指定 --api-files 参数")
|
|
268
|
+
logger.error("使用示例: har2pytest testcase --pattern batch --api-files apis/mall_mgmt_application/_mgmt_prmt_luckyActivity_luckyActivityList.py")
|
|
269
|
+
return
|
|
270
|
+
|
|
271
|
+
# 解析 API 文件列表(支持逗号分隔)
|
|
272
|
+
api_files_list = [f.strip() for f in api_files_arg.split(",")]
|
|
273
|
+
|
|
274
|
+
logger.info("批量生成测试用例(从API文件读取参数)")
|
|
275
|
+
logger.info(f"API文件数量: {len(api_files_list)}")
|
|
276
|
+
logger.info(f"任务ID: {task_id}")
|
|
277
|
+
logger.info("-" * 50)
|
|
278
|
+
|
|
279
|
+
generator = TestCaseGenerator(api_dir=api_dir, output_dir=output_dir)
|
|
280
|
+
result = await generator.generate_batch_testcases(api_files_list, task_id)
|
|
281
|
+
|
|
282
|
+
logger.info("-" * 50)
|
|
283
|
+
logger.info(f"总API文件数: {result['total']}")
|
|
284
|
+
logger.info(f"跳过(已存在): {result['skipped']}")
|
|
285
|
+
logger.info(f"成功生成: {result['generated']}")
|
|
286
|
+
logger.info(f"失败: {result['failed']}")
|
|
287
|
+
if result["generated_files"]:
|
|
288
|
+
logger.info("生成的文件:")
|
|
289
|
+
for f in result["generated_files"]:
|
|
290
|
+
logger.info(f" - {f.replace('\\', '/')}")
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
if __name__ == "__main__":
|
|
294
|
+
main()
|