iflow-mcp_galaxyxieyu_api-auto-test 0.1.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.
- atf/__init__.py +48 -0
- atf/assets/__init__.py +0 -0
- atf/assets/report.css +243 -0
- atf/auth.py +99 -0
- atf/case_generator.py +737 -0
- atf/conftest.py +65 -0
- atf/core/__init__.py +40 -0
- atf/core/assert_handler.py +336 -0
- atf/core/config_manager.py +111 -0
- atf/core/globals.py +52 -0
- atf/core/log_manager.py +52 -0
- atf/core/login_handler.py +60 -0
- atf/core/request_handler.py +189 -0
- atf/core/variable_resolver.py +212 -0
- atf/handlers/__init__.py +10 -0
- atf/handlers/notification_handler.py +101 -0
- atf/handlers/report_generator.py +160 -0
- atf/handlers/teardown_handler.py +106 -0
- atf/mcp/__init__.py +1 -0
- atf/mcp/executor.py +469 -0
- atf/mcp/models.py +532 -0
- atf/mcp/tools/__init__.py +1 -0
- atf/mcp/tools/health_tool.py +58 -0
- atf/mcp/tools/metrics_tools.py +132 -0
- atf/mcp/tools/runner_tools.py +380 -0
- atf/mcp/tools/testcase_tools.py +603 -0
- atf/mcp/tools/unittest_tools.py +189 -0
- atf/mcp/utils.py +376 -0
- atf/mcp_server.py +169 -0
- atf/runner.py +134 -0
- atf/unit_case_generator.py +337 -0
- atf/utils/__init__.py +2 -0
- atf/utils/helpers.py +155 -0
- iflow_mcp_galaxyxieyu_api_auto_test-0.1.0.dist-info/METADATA +409 -0
- iflow_mcp_galaxyxieyu_api_auto_test-0.1.0.dist-info/RECORD +37 -0
- iflow_mcp_galaxyxieyu_api_auto_test-0.1.0.dist-info/WHEEL +4 -0
- iflow_mcp_galaxyxieyu_api_auto_test-0.1.0.dist-info/entry_points.txt +2 -0
atf/utils/helpers.py
ADDED
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
"""
|
|
2
|
+
测试数据工厂 - 提供常用的数据生成函数
|
|
3
|
+
用法: {{ tools.timestamp() }}, {{ tools.uuid() }}, {{ tools.random_int(1, 100) }}
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import random
|
|
7
|
+
import string
|
|
8
|
+
import time
|
|
9
|
+
import uuid as _uuid
|
|
10
|
+
from datetime import datetime, timedelta
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
# ==================== 时间相关 ====================
|
|
14
|
+
|
|
15
|
+
def timestamp():
|
|
16
|
+
"""当前时间戳(秒)"""
|
|
17
|
+
return int(time.time())
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def timestamp_ms():
|
|
21
|
+
"""当前时间戳(毫秒)"""
|
|
22
|
+
return int(time.time() * 1000)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def datetime_now(fmt: str = "%Y-%m-%d %H:%M:%S"):
|
|
26
|
+
"""当前时间字符串"""
|
|
27
|
+
return datetime.now().strftime(fmt)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def date_today(fmt: str = "%Y-%m-%d"):
|
|
31
|
+
"""今天日期"""
|
|
32
|
+
return datetime.now().strftime(fmt)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def date_offset(days: int = 0, fmt: str = "%Y-%m-%d"):
|
|
36
|
+
"""偏移日期,days 可为负数"""
|
|
37
|
+
return (datetime.now() + timedelta(days=days)).strftime(fmt)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
# ==================== 随机数据 ====================
|
|
41
|
+
|
|
42
|
+
def uuid():
|
|
43
|
+
"""生成 UUID"""
|
|
44
|
+
return str(_uuid.uuid4())
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def uuid_short():
|
|
48
|
+
"""生成短 UUID(8位)"""
|
|
49
|
+
return str(_uuid.uuid4())[:8]
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def random_int(min_val: int = 1, max_val: int = 10000):
|
|
53
|
+
"""随机整数"""
|
|
54
|
+
return random.randint(min_val, max_val)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def random_float(min_val: float = 0.0, max_val: float = 100.0, precision: int = 2):
|
|
58
|
+
"""随机浮点数"""
|
|
59
|
+
return round(random.uniform(min_val, max_val), precision)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def random_str(length: int = 8):
|
|
63
|
+
"""随机字符串(字母+数字)"""
|
|
64
|
+
return ''.join(random.choices(string.ascii_letters + string.digits, k=length))
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def random_letters(length: int = 8):
|
|
68
|
+
"""随机字母"""
|
|
69
|
+
return ''.join(random.choices(string.ascii_letters, k=length))
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def random_digits(length: int = 6):
|
|
73
|
+
"""随机数字字符串"""
|
|
74
|
+
return ''.join(random.choices(string.digits, k=length))
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def random_choice(*items):
|
|
78
|
+
"""从给定选项中随机选择"""
|
|
79
|
+
return random.choice(items) if items else None
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
# ==================== 模拟数据 ====================
|
|
83
|
+
|
|
84
|
+
def fake_email(prefix: str = "test"):
|
|
85
|
+
"""生成测试邮箱"""
|
|
86
|
+
return f"{prefix}_{timestamp()}@test.com"
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def fake_phone():
|
|
90
|
+
"""生成测试手机号(中国)"""
|
|
91
|
+
prefixes = ['138', '139', '150', '151', '152', '158', '159', '186', '187', '188']
|
|
92
|
+
return random.choice(prefixes) + random_digits(8)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def fake_username(prefix: str = "user"):
|
|
96
|
+
"""生成测试用户名"""
|
|
97
|
+
return f"{prefix}_{uuid_short()}"
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def fake_name():
|
|
101
|
+
"""生成随机中文姓名"""
|
|
102
|
+
first_names = ['张', '李', '王', '刘', '陈', '杨', '赵', '黄', '周', '吴']
|
|
103
|
+
last_names = ['伟', '芳', '娜', '敏', '静', '强', '磊', '洋', '勇', '艳', '杰', '娟', '涛', '明', '超']
|
|
104
|
+
return random.choice(first_names) + ''.join(random.choices(last_names, k=random.randint(1, 2)))
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def fake_address():
|
|
108
|
+
"""生成随机地址"""
|
|
109
|
+
cities = ['北京市', '上海市', '广州市', '深圳市', '杭州市', '成都市', '武汉市', '南京市']
|
|
110
|
+
districts = ['朝阳区', '海淀区', '浦东新区', '天河区', '南山区', '西湖区', '武侯区', '江宁区']
|
|
111
|
+
streets = ['科技路', '创新大道', '人民路', '中山路', '解放路', '建设路']
|
|
112
|
+
return f"{random.choice(cities)}{random.choice(districts)}{random.choice(streets)}{random_int(1, 999)}号"
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def fake_id_card():
|
|
116
|
+
"""生成测试身份证号(非真实)"""
|
|
117
|
+
area = random_digits(6)
|
|
118
|
+
year = random.randint(1970, 2000)
|
|
119
|
+
month = str(random.randint(1, 12)).zfill(2)
|
|
120
|
+
day = str(random.randint(1, 28)).zfill(2)
|
|
121
|
+
seq = random_digits(3)
|
|
122
|
+
check = random.choice('0123456789X')
|
|
123
|
+
return f"{area}{year}{month}{day}{seq}{check}"
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def fake_company():
|
|
127
|
+
"""生成测试公司名"""
|
|
128
|
+
prefixes = ['华', '中', '东', '西', '南', '北', '新', '金', '银', '瑞']
|
|
129
|
+
mids = ['科', '创', '智', '信', '达', '联', '通', '盛', '鑫', '源']
|
|
130
|
+
suffixes = ['科技有限公司', '网络有限公司', '信息技术有限公司', '电子商务有限公司']
|
|
131
|
+
return random.choice(prefixes) + random.choice(mids) + random.choice(suffixes)
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
# ==================== 兼容旧函数 ====================
|
|
135
|
+
|
|
136
|
+
def demo_get_id():
|
|
137
|
+
"""兼容旧版本"""
|
|
138
|
+
return random_int(1, 1000)
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def demo_func(a=None, b=None, c=None):
|
|
142
|
+
"""兼容旧版本"""
|
|
143
|
+
vals = [v for v in [a, b, c] if v is not None]
|
|
144
|
+
return sum(vals) if vals else 0
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
# ==================== 使用示例 ====================
|
|
148
|
+
if __name__ == '__main__':
|
|
149
|
+
print(f"timestamp: {timestamp()}")
|
|
150
|
+
print(f"uuid: {uuid()}")
|
|
151
|
+
print(f"random_int: {random_int(1, 100)}")
|
|
152
|
+
print(f"fake_email: {fake_email()}")
|
|
153
|
+
print(f"fake_phone: {fake_phone()}")
|
|
154
|
+
print(f"fake_name: {fake_name()}")
|
|
155
|
+
print(f"fake_address: {fake_address()}")
|
|
@@ -0,0 +1,409 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: iflow-mcp_galaxyxieyu_api-auto-test
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: API Auto Test Framework with MCP Server
|
|
5
|
+
Author-email: GalaxyXieyu <galaxyxieyu@github.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Keywords: api,automation,mcp,pytest,testing
|
|
8
|
+
Classifier: Development Status :: 4 - Beta
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Requires-Python: >=3.10
|
|
16
|
+
Requires-Dist: allure-pytest>=2.13
|
|
17
|
+
Requires-Dist: dingtalkchatbot>=1.5.7
|
|
18
|
+
Requires-Dist: loguru>=0.4.1
|
|
19
|
+
Requires-Dist: mcp>=1.0.0
|
|
20
|
+
Requires-Dist: mysql-connector-python>=8.0.33
|
|
21
|
+
Requires-Dist: pydantic>=2.0
|
|
22
|
+
Requires-Dist: pytest-html>=2.1.1
|
|
23
|
+
Requires-Dist: pytest>=7.0
|
|
24
|
+
Requires-Dist: pyyaml>=6.0
|
|
25
|
+
Requires-Dist: requests>=2.31
|
|
26
|
+
Requires-Dist: urllib3<2
|
|
27
|
+
Description-Content-Type: text/markdown
|
|
28
|
+
|
|
29
|
+
<div align="center">
|
|
30
|
+
<img src="docs/images/mcp-architecture.png" alt="MCP Architecture" width="100%"/>
|
|
31
|
+
</div>
|
|
32
|
+
|
|
33
|
+
# API Auto Test Framework
|
|
34
|
+
|
|
35
|
+

|
|
36
|
+

|
|
37
|
+

|
|
38
|
+
|
|
39
|
+
**YAML Declarative API Testing Framework, Optimized for AI Coding Assistants**
|
|
40
|
+
|
|
41
|
+
[Quick Start](#quick-start) | [MCP Integration](#mcp-server-integration) | [YAML Spec](#yaml-test-case-spec) | [Unit Testing](#unit-testing)
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## Why This Framework?
|
|
46
|
+
|
|
47
|
+
When asking AI to write API tests, you might encounter these issues:
|
|
48
|
+
|
|
49
|
+
**Scenario 1: Repetitive Work**
|
|
50
|
+
|
|
51
|
+
Every time you ask AI to generate tests, you need to re-describe the project structure, authentication method, and assertion style. For 10 API tests, the same fixture and setup code gets generated 10 times.
|
|
52
|
+
|
|
53
|
+
**Scenario 2: Token Black Hole**
|
|
54
|
+
|
|
55
|
+
A simple login API test generates 200 lines of code. You find an assertion is wrong, ask AI to fix it, and it generates another 200 lines. After 3 revisions, you've consumed 2000+ Tokens, and you still end up fixing it manually.
|
|
56
|
+
|
|
57
|
+
**Scenario 3: Debugging Dead Loop**
|
|
58
|
+
|
|
59
|
+
AI-generated tests fail to run. You paste the error message, AI fixes it but still wrong. After 5 rounds of conversation, the problem persists, and you've burned 5000+ Tokens.
|
|
60
|
+
|
|
61
|
+
**This Framework's Solution:**
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
Traditional: Natural Language -> AI Generates Full Code -> Run Error -> Paste Error -> AI Regenerates -> Loop...
|
|
65
|
+
This Framework: Natural Language -> AI Generates YAML -> Framework Executes -> Locate Issue -> Fix 1 Line YAML
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
| Metric | Traditional AI | This Framework |
|
|
69
|
+
|--------|---------------|----------------|
|
|
70
|
+
| Test 1 API | ~200 lines code | ~20 lines YAML |
|
|
71
|
+
| Modify Assertion | Regenerate all code | Fix 1-2 lines YAML |
|
|
72
|
+
| 10 API Tests | Repeat setup 10x | Shared config, 0 repeat |
|
|
73
|
+
| Debug Issue | 3-5 rounds avg | Usually 1 round |
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## Key Features
|
|
78
|
+
|
|
79
|
+
| Feature | Description |
|
|
80
|
+
|---------|-------------|
|
|
81
|
+
| **YAML Declarative Tests** | Test logic separated from execution code, AI generates structured data only |
|
|
82
|
+
| **MCP Server** | Seamless integration with Claude/Cursor and other AI editors |
|
|
83
|
+
| **API Workflow Orchestration** | Multi-step API calls in single file, with data passing and assertions between steps |
|
|
84
|
+
| **Variable Resolution Engine** | Support for cross-step data transfer, global variables, and dynamic function calls |
|
|
85
|
+
| **Auto Authentication** | Token acquisition and refresh handled by framework |
|
|
86
|
+
| **Data Factory** | Built-in mock data generation, no Java dependencies |
|
|
87
|
+
| **Multi-format Reports** | Allure (offline/online), pytest-html (standalone HTML, styled) |
|
|
88
|
+
| **Multi-channel Notifications** | DingTalk, Feishu, WeCom |
|
|
89
|
+
| **Unit Testing** | Python code unit testing with automatic mock dependency injection |
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## Quick Start
|
|
94
|
+
|
|
95
|
+
### Installation
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
# 1. Install uv (if not installed)
|
|
99
|
+
curl -LsSf https://astral.sh/uv/install.sh | sh
|
|
100
|
+
|
|
101
|
+
# 2. Install MCP server (recommended: install as a tool)
|
|
102
|
+
uv tool install git+https://github.com/GalaxyXieyu/Api-Test-MCP.git
|
|
103
|
+
|
|
104
|
+
# Verify
|
|
105
|
+
api-auto-test-mcp --help
|
|
106
|
+
|
|
107
|
+
# Manage tools
|
|
108
|
+
uv tool list
|
|
109
|
+
uv tool uninstall api-auto-test # use the tool name shown by `uv tool list`
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
**Run without installing (uvx):**
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
uvx --from git+https://github.com/GalaxyXieyu/Api-Test-MCP.git api-auto-test-mcp --help
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
**Common mistake:** `uvx install ...` is **wrong**. `uvx` treats the first word after it as the tool name, so it will try to resolve a package literally named `install` and fail.
|
|
119
|
+
|
|
120
|
+
### Configure Editor
|
|
121
|
+
|
|
122
|
+
Add the following to your editor's MCP settings:
|
|
123
|
+
|
|
124
|
+
```json
|
|
125
|
+
{
|
|
126
|
+
"mcpServers": {
|
|
127
|
+
"api-auto-test": {
|
|
128
|
+
"command": "api-auto-test-mcp"
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
| Editor | Config Location |
|
|
135
|
+
|--------|-----------------|
|
|
136
|
+
| Claude Desktop | `~/Library/Application Support/Claude/claude_desktop_config.json` |
|
|
137
|
+
| Cursor | Settings -> MCP Servers |
|
|
138
|
+
| VSCode + Continue | `.vscode/mcp.json` |
|
|
139
|
+
|
|
140
|
+
### Local Development
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
# Recommended with uv
|
|
144
|
+
uv pip install -r requirements.txt
|
|
145
|
+
|
|
146
|
+
# Or with pip
|
|
147
|
+
pip install -r requirements.txt
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### Create Test Case
|
|
151
|
+
|
|
152
|
+
```yaml
|
|
153
|
+
# tests/cases/user_login.yaml
|
|
154
|
+
testcase:
|
|
155
|
+
name: user_login
|
|
156
|
+
description: User login API test
|
|
157
|
+
host: http://localhost:8000
|
|
158
|
+
steps:
|
|
159
|
+
- id: login
|
|
160
|
+
path: /api/auth/login
|
|
161
|
+
method: POST
|
|
162
|
+
data:
|
|
163
|
+
username: "test_user"
|
|
164
|
+
password: "123456"
|
|
165
|
+
assert:
|
|
166
|
+
- type: status_code
|
|
167
|
+
expected: 200
|
|
168
|
+
- type: equals
|
|
169
|
+
field: data.code
|
|
170
|
+
expected: 0
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### Generate and Run
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
# Generate pytest scripts
|
|
177
|
+
python -m atf.case_generator
|
|
178
|
+
|
|
179
|
+
# Run tests
|
|
180
|
+
pytest tests/scripts/ -v
|
|
181
|
+
|
|
182
|
+
# Generate Allure report
|
|
183
|
+
pytest tests/scripts/ --alluredir=tests/allure-results
|
|
184
|
+
allure serve tests/allure-results
|
|
185
|
+
|
|
186
|
+
# Generate pytest-html report
|
|
187
|
+
pytest tests/scripts/ --html=report.html
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
## MCP Server Integration
|
|
193
|
+
|
|
194
|
+
Through MCP, AI editors can directly call framework tools to generate and execute tests.
|
|
195
|
+
|
|
196
|
+
### Efficiency Comparison
|
|
197
|
+
|
|
198
|
+
| Metric | Without MCP | With MCP | Improvement |
|
|
199
|
+
|--------|-------------|----------|-------------|
|
|
200
|
+
| Total Cost | $0.0214 | $0.0099 | **-54%** |
|
|
201
|
+
| API Latency | 11 sec | 4 sec | **-64%** |
|
|
202
|
+
| Output Tokens | 585 | 238 | **-59%** |
|
|
203
|
+
| Cache Read | 42.0k | 21.0k | **-50%** |
|
|
204
|
+
|
|
205
|
+
**Test Scenario**: Same API test generation task (pure consultation/analysis conversation)
|
|
206
|
+
|
|
207
|
+
**Core Advantages**:
|
|
208
|
+
- **54% cost reduction**: MCP directly calls tools, avoiding lengthy code generation context
|
|
209
|
+
- **64% faster API response**: Tool calls are more efficient than natural language interaction
|
|
210
|
+
- **59% less token consumption**: Only necessary parameters needed, no need to repeat project structure
|
|
211
|
+
|
|
212
|
+
### Available Tools
|
|
213
|
+
|
|
214
|
+
| Tool | Description |
|
|
215
|
+
|------|-------------|
|
|
216
|
+
| `list_testcases` | List test cases |
|
|
217
|
+
| `get_testcase` | Read test case content |
|
|
218
|
+
| `write_testcase` | Create/update test case and generate pytest script |
|
|
219
|
+
| `write_unittest` | Create unit test |
|
|
220
|
+
| `delete_testcase` | Delete test case |
|
|
221
|
+
| `run_tests` | Execute tests |
|
|
222
|
+
| `get_test_results` | Get test execution history |
|
|
223
|
+
| `health_check` | Service health check |
|
|
224
|
+
|
|
225
|
+
### Usage Example
|
|
226
|
+
|
|
227
|
+
Tell AI:
|
|
228
|
+
|
|
229
|
+
```
|
|
230
|
+
Create a test for /api/users interface, verify returned user list length > 0
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
AI will call `write_testcase` to generate YAML and corresponding pytest script.
|
|
234
|
+
|
|
235
|
+
---
|
|
236
|
+
|
|
237
|
+
## Project Structure
|
|
238
|
+
|
|
239
|
+
```
|
|
240
|
+
api-auto-test/
|
|
241
|
+
├── atf/ # Framework core
|
|
242
|
+
│ ├── core/ # Request, assertion, variable resolution modules
|
|
243
|
+
│ ├── mcp/ # MCP Server implementation
|
|
244
|
+
│ └── handlers/ # Notification, report handlers
|
|
245
|
+
├── tests/
|
|
246
|
+
│ ├── cases/ # YAML test cases
|
|
247
|
+
│ └── scripts/ # Generated pytest scripts
|
|
248
|
+
├── config.yaml # Project config (environment, database, notifications)
|
|
249
|
+
└── pyproject.toml
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
---
|
|
253
|
+
|
|
254
|
+
## YAML Test Case Spec
|
|
255
|
+
|
|
256
|
+
### Basic Structure
|
|
257
|
+
|
|
258
|
+
```yaml
|
|
259
|
+
testcase:
|
|
260
|
+
name: test_name # Case name, used for filename
|
|
261
|
+
description: Description # Optional
|
|
262
|
+
host: http://localhost:8000 # API host, can also be configured globally in config.yaml
|
|
263
|
+
steps:
|
|
264
|
+
- id: step1 # Step ID, used for later reference
|
|
265
|
+
path: /api/endpoint
|
|
266
|
+
method: POST
|
|
267
|
+
headers:
|
|
268
|
+
Authorization: "Bearer {{ login.data.token }}" # Reference response from other step
|
|
269
|
+
data:
|
|
270
|
+
key: value
|
|
271
|
+
assert:
|
|
272
|
+
- type: status_code
|
|
273
|
+
expected: 200
|
|
274
|
+
- type: equals
|
|
275
|
+
field: data.id
|
|
276
|
+
expected: 1
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
### Assertion Types
|
|
280
|
+
|
|
281
|
+
| Type | Description | Example |
|
|
282
|
+
|------|-------------|---------|
|
|
283
|
+
| `status_code` | HTTP status code | `expected: 200` |
|
|
284
|
+
| `equals` | Exact match | `field: data.id, expected: 1` |
|
|
285
|
+
| `contains` | Contains | `field: data.name, expected: "test"` |
|
|
286
|
+
| `length` | Array/string length | `field: data.list, expected: 10` |
|
|
287
|
+
| `regex` | Regex match | `field: data.email, expected: "^\\w+@"` |
|
|
288
|
+
|
|
289
|
+
### Variable Reference
|
|
290
|
+
|
|
291
|
+
```yaml
|
|
292
|
+
# Reference response data from other steps
|
|
293
|
+
token: "{{ login.data.token }}"
|
|
294
|
+
|
|
295
|
+
# Reference global config
|
|
296
|
+
host: "{{ merchant.host }}"
|
|
297
|
+
|
|
298
|
+
# Call built-in functions
|
|
299
|
+
timestamp: "{{ tools.get_timestamp() }}"
|
|
300
|
+
uuid: "{{ tools.generate_uuid() }}"
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
### Teardown
|
|
304
|
+
|
|
305
|
+
```yaml
|
|
306
|
+
testcase:
|
|
307
|
+
name: create_and_delete_user
|
|
308
|
+
steps:
|
|
309
|
+
- id: create_user
|
|
310
|
+
path: /api/users
|
|
311
|
+
method: POST
|
|
312
|
+
data:
|
|
313
|
+
name: "test_user"
|
|
314
|
+
teardowns:
|
|
315
|
+
- id: delete_user
|
|
316
|
+
operation_type: api
|
|
317
|
+
path: /api/users/{{ create_user.data.id }}
|
|
318
|
+
method: DELETE
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
---
|
|
322
|
+
|
|
323
|
+
## Unit Testing
|
|
324
|
+
|
|
325
|
+
Support for writing unit tests for Python code, automatically generating test cases through MCP tools.
|
|
326
|
+
|
|
327
|
+
### Unit Test YAML Format
|
|
328
|
+
|
|
329
|
+
```yaml
|
|
330
|
+
unittest:
|
|
331
|
+
name: UserService Test
|
|
332
|
+
target:
|
|
333
|
+
module: app.services.user_service
|
|
334
|
+
class: UserService
|
|
335
|
+
function: get_user
|
|
336
|
+
fixtures:
|
|
337
|
+
setup:
|
|
338
|
+
- type: patch
|
|
339
|
+
target: app.services.user_service.UserRepository
|
|
340
|
+
return_value:
|
|
341
|
+
id: 1
|
|
342
|
+
name: "test_user"
|
|
343
|
+
cases:
|
|
344
|
+
- id: test_get_user_success
|
|
345
|
+
description: Test get user success
|
|
346
|
+
inputs:
|
|
347
|
+
args: [1]
|
|
348
|
+
kwargs: {}
|
|
349
|
+
assert:
|
|
350
|
+
- type: equals
|
|
351
|
+
field: result.id
|
|
352
|
+
expected: 1
|
|
353
|
+
- type: equals
|
|
354
|
+
field: result.name
|
|
355
|
+
expected: "test_user"
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
### Assertion Types
|
|
359
|
+
|
|
360
|
+
| Type | Description |
|
|
361
|
+
|------|-------------|
|
|
362
|
+
| `equals` | Exact match |
|
|
363
|
+
| `not_equals` | Not equal |
|
|
364
|
+
| `contains` | Contains |
|
|
365
|
+
| `raises` | Expect exception to be raised |
|
|
366
|
+
| `is_none` | Result is None |
|
|
367
|
+
| `is_not_none` | Result is not None |
|
|
368
|
+
| `called_once` | Mock called once |
|
|
369
|
+
| `called_with` | Mock called with specific arguments |
|
|
370
|
+
|
|
371
|
+
---
|
|
372
|
+
|
|
373
|
+
## Configuration File
|
|
374
|
+
|
|
375
|
+
```yaml
|
|
376
|
+
# config.yaml
|
|
377
|
+
projects:
|
|
378
|
+
merchant:
|
|
379
|
+
test:
|
|
380
|
+
host: http://192.168.1.100:8080
|
|
381
|
+
is_need_login: true
|
|
382
|
+
login:
|
|
383
|
+
url: http://192.168.1.100:8080/login
|
|
384
|
+
method: POST
|
|
385
|
+
data:
|
|
386
|
+
username: admin
|
|
387
|
+
password: "123456"
|
|
388
|
+
online:
|
|
389
|
+
host: https://api.example.com
|
|
390
|
+
is_need_login: true
|
|
391
|
+
|
|
392
|
+
notifications:
|
|
393
|
+
dingtalk:
|
|
394
|
+
webhook: "https://oapi.dingtalk.com/robot/send?access_token=xxx"
|
|
395
|
+
secret: "SECxxx"
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
---
|
|
399
|
+
|
|
400
|
+
## License
|
|
401
|
+
|
|
402
|
+
MIT License
|
|
403
|
+
|
|
404
|
+
---
|
|
405
|
+
|
|
406
|
+
## Links
|
|
407
|
+
|
|
408
|
+
- [GitHub](https://github.com/GalaxyXieyu/Api-Test-MCP)
|
|
409
|
+
- [Issue Report](https://github.com/GalaxyXieyu/Api-Test-MCP/issues)
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
atf/__init__.py,sha256=QetjM3D_EbtvBwNjUDYwmdrJUun2eBaO1m6St5CWT88,1191
|
|
2
|
+
atf/auth.py,sha256=DCMPDAz1Vnoj7hxuWRRfZ0ug-kb4e9Ey4nnhDVw6LRk,3293
|
|
3
|
+
atf/case_generator.py,sha256=nRTI6WNi3DSvtn7UFZ11utaNLsNJX0wIWSLdRwWNS8E,30026
|
|
4
|
+
atf/conftest.py,sha256=XRUQSHB_UAdLEt3-yPQxm84TQqwZ0yLqxnFMOzi24UA,2219
|
|
5
|
+
atf/mcp_server.py,sha256=GJHBIjpPX8p0xS9bqunjfNurLcWs-gcyS0nNTMbFIa8,4857
|
|
6
|
+
atf/runner.py,sha256=OqFkBUVvfL9nR9LoepmNrq07XK2k3eRDYZJm1qYeZIY,5281
|
|
7
|
+
atf/unit_case_generator.py,sha256=paIAgxv6kCvZJRSiWYlzOFhH8zsXIB7OnAAOOqMc9DY,12464
|
|
8
|
+
atf/assets/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
9
|
+
atf/assets/report.css,sha256=ALlK-Sjom1CntJAfBhnHUmET78-VvJ8HS4cdQed145g,4818
|
|
10
|
+
atf/core/__init__.py,sha256=l1aHMcuadmCsEUuxCQLYEC1A8AZs3fEKJwixDabh120,1007
|
|
11
|
+
atf/core/assert_handler.py,sha256=TyvlOONdEeAZsCLRFjUHrDIrLdOiwwQCiu4hEDbZMK4,14745
|
|
12
|
+
atf/core/config_manager.py,sha256=haCEunh6fd_H5VbScH96vlea2HOT38ItNrWfNG29lr8,3952
|
|
13
|
+
atf/core/globals.py,sha256=7rfXhfpUoK8K3x6i90WKePEgxFEigipzMl1PtCs95RQ,1350
|
|
14
|
+
atf/core/log_manager.py,sha256=sJcVZL2NAVQE5BV4BOCkAMTpGlUa_K4KDq3g12XK25M,1584
|
|
15
|
+
atf/core/login_handler.py,sha256=9Y7b7j_4xGyuswgzzgW58GHSnw-yR91fIOa2aiVYGPc,2363
|
|
16
|
+
atf/core/request_handler.py,sha256=sGV7EXdPJslJEZBGxp4dzrbqTXC9hiz28DF670ccnh0,8035
|
|
17
|
+
atf/core/variable_resolver.py,sha256=QNKIUNPAj6C5JGwSyVnba4YCN2Ur1r459wTxqrZOLkE,6617
|
|
18
|
+
atf/handlers/__init__.py,sha256=ClFew48CqBCtXDt3bG8XLib8_zLVmL0WVrNFGrazCII,252
|
|
19
|
+
atf/handlers/notification_handler.py,sha256=67xQbiPYr8wjq9KGrkgoxnnAnuOjBFrYRD6xybxFB0w,3189
|
|
20
|
+
atf/handlers/report_generator.py,sha256=NA-y_378Gud5oEdtI00B1fiq8TpfpK1jh4oizdTqL2E,6431
|
|
21
|
+
atf/handlers/teardown_handler.py,sha256=93kS2BrO_OilXbhOWgpUkSaZeLyiKrEFtwkl8jGbbsU,3328
|
|
22
|
+
atf/mcp/__init__.py,sha256=fZsU_7U8cOD1nFGAGfDkQkbkqTGP6MIfyQu3V_avYWM,21
|
|
23
|
+
atf/mcp/executor.py,sha256=LE1CowMJJ8tFaeKGJbOSYrKJBBv2E9otl7URDnwAFjI,16112
|
|
24
|
+
atf/mcp/models.py,sha256=_MSSibvcwWwSEHfOsoZPhaCJgkgFfZcWT7TLPf8yS9A,16330
|
|
25
|
+
atf/mcp/utils.py,sha256=OnmGjvk05PD5fzP_IgAIKinKCfAaKkfIOfF7WtjcEOQ,12327
|
|
26
|
+
atf/mcp/tools/__init__.py,sha256=WOt8D_cjUg7poNypfi_C21hfdbitOmXM2VLuyTuLL5I,20
|
|
27
|
+
atf/mcp/tools/health_tool.py,sha256=fvcEh6G0ZU_ERRY2PGZiBvHG0o3eAfGT1edwQXNEFlw,1685
|
|
28
|
+
atf/mcp/tools/metrics_tools.py,sha256=QfmaTzCd1Db-BjrZB6m2zK2IWu21qqVSH1h9t7jXFLI,4451
|
|
29
|
+
atf/mcp/tools/runner_tools.py,sha256=TTUnTrHwvEXe6PWtFqRzXOvdadD_d_jg0jNqhME3D7g,15016
|
|
30
|
+
atf/mcp/tools/testcase_tools.py,sha256=w0XzQzD4IMlbJP7ruJ0Z008lJuB5vruzX1srx1KMrUg,25602
|
|
31
|
+
atf/mcp/tools/unittest_tools.py,sha256=nL5G7gfrU7aCK1glJfcJWp8nu2ykhYmjWpGB3-Lb2h0,7764
|
|
32
|
+
atf/utils/__init__.py,sha256=3WjDRQfBXan1IRUDDZGIy4zFocdvXBV8fPtU1pTuBME,66
|
|
33
|
+
atf/utils/helpers.py,sha256=YyzZpGjI5wUNk7WxujHrTf_QX-8QVfemqOWyYXouF2o,4720
|
|
34
|
+
iflow_mcp_galaxyxieyu_api_auto_test-0.1.0.dist-info/METADATA,sha256=TrL-E8am3fUe7Pm7VMKwL5KX_lfYj23DDO0xbn_C11k,11310
|
|
35
|
+
iflow_mcp_galaxyxieyu_api_auto_test-0.1.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
36
|
+
iflow_mcp_galaxyxieyu_api_auto_test-0.1.0.dist-info/entry_points.txt,sha256=U0JuJR1z3QNxTQO1Un8YSQy1dQvqXkwLwxAd0K13peY,76
|
|
37
|
+
iflow_mcp_galaxyxieyu_api_auto_test-0.1.0.dist-info/RECORD,,
|