zhouhui.jiang

接口API测试

{
"token": "eyJhbGciOiJIUzUxMiJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwic3ViIjoiYWRtaW4iLCJpYXQiOjE3NjAwMDM1NjMsImV4cCI6MTc2MDA4OTk2M30.KnogGaxl7mYGJTZnXk0tY8ohvNHy8jcR2mMd7p_Nz_iMqSYngtDJa4t84XuSIeaj6uhBGRXi1Mamufo2Nf8BYQ",
"saved_at": 1760003563
}
\ No newline at end of file
# API 测试脚本
基于 Python 3.7.8 的 Apple ERP 系统 API 接口测试脚本。
## 环境要求
- Python 3.7.8+
- requests 库
```bash
pip install requests
```
## 配置
- 默认API基地址:`http://localhost:8083`
- 默认登录账号:`admin`
- 默认登录密码:`password`
可通过环境变量 `API_BASE_URL` 修改基地址:
```bash
export API_BASE_URL=http://your-server:8083
```
## 使用方法
### 1. 单独运行测试
```bash
# 登录测试(获取并保存token)
python test_auth.py
# 用户管理测试
python test_users.py
# 角色管理测试
python test_roles.py
# 菜单管理测试
python test_menus.py
# 字典管理测试
python test_dicts.py
```
### 2. 一键运行所有测试
```bash
python run_all_tests.py
```
### 3. 自定义登录账号
```bash
python test_auth.py your_username your_password
```
## 测试内容
### 认证管理 (test_auth.py)
- 用户登录
- 获取并保存JWT token
- 打印token供后续使用
### 用户管理 (test_users.py)
- 获取用户列表
- 新增用户(含模拟数据)
- 编辑用户信息
- 重置用户密码
- 修改用户状态
- 删除用户
### 角色管理 (test_roles.py)
- 获取角色列表
- 新增角色(含模拟数据)
- 编辑角色信息
- 修改角色状态
- 删除角色
### 菜单管理 (test_menus.py)
- 获取菜单列表(占位实现,需根据实际接口调整)
### 字典管理 (test_dicts.py)
- 获取字典列表(占位实现,需根据实际接口调整)
## 注意事项
1. **Token管理**:登录成功后,token会自动保存到 `.token.json` 文件中,后续请求会自动携带。
2. **模拟数据**:用户和角色测试使用随机生成的模拟数据,避免与现有数据冲突。
3. **菜单和字典**:由于API文档中未找到明确的接口定义,当前为占位实现。如有具体接口路径,请修改对应脚本。
4. **错误处理**:脚本包含基本的错误处理和状态码检查。
## 文件说明
- `client.py` - API客户端封装类
- `test_auth.py` - 认证登录测试
- `test_users.py` - 用户管理测试
- `test_roles.py` - 角色管理测试
- `test_menus.py` - 菜单管理测试(占位)
- `test_dicts.py` - 字典管理测试(占位)
- `run_all_tests.py` - 一键运行所有测试
- `.token.json` - 自动生成的token存储文件(运行后产生)
## 扩展
如需添加更多接口测试,可参考现有脚本结构:
1. 创建新的测试文件
2. 使用 `ApiClient` 类进行请求
3. 添加模拟数据生成
4. 包含错误处理和状态检查
"""API tests package (Python 3.7.8 compatible)."""
No preview for this file type
import json
import os
import time
from typing import Dict, Optional
import requests
class ApiClient:
def __init__(self, base_url: str):
self.base_url = base_url.rstrip('/')
self.session = requests.Session()
self.token_path = os.path.join(os.path.dirname(__file__), '.token.json')
self.token: Optional[str] = None
self._load_token()
def _load_token(self) -> None:
if os.path.exists(self.token_path):
try:
with open(self.token_path, 'r', encoding='utf-8') as f:
data = json.load(f)
self.token = data.get('token')
except Exception:
self.token = None
def _save_token(self, token: str) -> None:
self.token = token
data = {
'token': token,
'saved_at': int(time.time())
}
with open(self.token_path, 'w', encoding='utf-8') as f:
json.dump(data, f, ensure_ascii=False, indent=2)
def set_token(self, token: str) -> None:
self._save_token(token)
def _headers(self, extra: Optional[Dict[str, str]] = None) -> Dict[str, str]:
headers: Dict[str, str] = {
'Content-Type': 'application/json'
}
if self.token:
headers['Authorization'] = f'Bearer {self.token}'
if extra:
headers.update(extra)
return headers
def post(self, path: str, json_body: Dict, auth: bool = True) -> requests.Response:
url = f"{self.base_url}{path}"
headers = self._headers() if auth else {'Content-Type': 'application/json'}
return self.session.post(url, headers=headers, json=json_body, timeout=30)
def get(self, path: str, params: Optional[Dict] = None, auth: bool = True) -> requests.Response:
url = f"{self.base_url}{path}"
headers = self._headers() if auth else {}
return self.session.get(url, headers=headers, params=params or {}, timeout=30)
def put(self, path: str, json_body: Dict, auth: bool = True) -> requests.Response:
url = f"{self.base_url}{path}"
headers = self._headers() if auth else {'Content-Type': 'application/json'}
return self.session.put(url, headers=headers, json=json_body, timeout=30)
def delete(self, path: str, auth: bool = True) -> requests.Response:
url = f"{self.base_url}{path}"
headers = self._headers() if auth else {}
return self.session.delete(url, headers=headers, timeout=30)
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
运行所有API测试脚本
Python 3.7.8 兼容
"""
import os
import sys
import subprocess
from typing import List, Tuple
def run_script(script_path: str, args: List[str] = None) -> Tuple[bool, str]:
"""运行单个测试脚本"""
cmd = [sys.executable, script_path]
if args:
cmd.extend(args)
try:
result = subprocess.run(
cmd,
capture_output=True,
text=True,
cwd=os.path.dirname(__file__)
)
return result.returncode == 0, result.stdout + result.stderr
except Exception as e:
return False, str(e)
def main():
"""主函数:按顺序运行所有测试"""
print("=" * 60)
print("Apple ERP API 测试套件")
print("=" * 60)
# 测试脚本列表(按执行顺序)
tests = [
("认证登录测试", "test_auth.py", ["admin", "password"]),
("用户管理测试", "test_users.py", []),
("角色管理测试", "test_roles.py", []),
("菜单管理测试", "test_menus.py", []),
("字典管理测试", "test_dicts.py", []),
]
success_count = 0
total_count = len(tests)
for test_name, script_name, args in tests:
print(f"\n{'='*20} {test_name} {'='*20}")
script_path = os.path.join(os.path.dirname(__file__), script_name)
if not os.path.exists(script_path):
print(f"❌ 脚本不存在: {script_path}")
continue
success, output = run_script(script_path, args)
if success:
print(f"✅ {test_name} 执行成功")
success_count += 1
else:
print(f"❌ {test_name} 执行失败")
# 显示输出(截取前500字符避免过长)
if output:
print("输出:")
print(output[:500] + ("..." if len(output) > 500 else ""))
# 总结
print("\n" + "=" * 60)
print(f"测试完成: {success_count}/{total_count} 个测试通过")
print("=" * 60)
if success_count == total_count:
print("🎉 所有测试都通过了!")
return 0
else:
print("⚠️ 部分测试失败,请检查输出信息")
return 1
if __name__ == "__main__":
sys.exit(main())
import os
import sys
from typing import Tuple
from client import ApiClient
BASE_URL = os.environ.get('API_BASE_URL', 'http://localhost:8083')
def login_and_print_token(username: str, password: str) -> Tuple[bool, str]:
client = ApiClient(BASE_URL)
resp = client.post('/api/auth/login', {
'username': username,
'password': password
}, auth=False)
try:
data = resp.json()
except Exception:
print('登录接口返回非JSON,status=', resp.status_code)
print(resp.text)
return False, ''
if resp.status_code == 200 and isinstance(data, dict) and data.get('code') == 200:
token = (data.get('data') or {}).get('token')
if token:
print('登录成功,token=')
print(token)
client.set_token(token)
return True, token
print('登录成功但未返回token,完整返回:', data)
return False, ''
print('登录失败:', data)
return False, ''
if __name__ == '__main__':
# 默认账户可根据实际系统修改
username = sys.argv[1] if len(sys.argv) > 1 else 'admin'
password = sys.argv[2] if len(sys.argv) > 2 else 'password'
success, _ = login_and_print_token(username, password)
sys.exit(0 if success else 1)
from client import ApiClient
def run_dict_tests(base_url: str = 'http://localhost:8083') -> None:
client = ApiClient(base_url)
# 文档未找到明确的字典接口路径,这里提供占位尝试
possible_list = ['/api/system/dict/list', '/api/dict/list']
for path in possible_list:
resp = client.get(path)
print('字典列表(尝试路径=', path, ') status=', resp.status_code)
print(resp.text)
if resp.status_code == 200:
break
if __name__ == '__main__':
run_dict_tests()
from client import ApiClient
def run_menu_tests(base_url: str = 'http://localhost:8083') -> None:
client = ApiClient(base_url)
# 文档未提供菜单接口明确定义,这里给出占位:如有具体端点,请替换下列路径
# 示例:GET 列表、POST 新增、POST 编辑、DELETE 删除
possible_list = ['/api/system/menu/list', '/api/menu/list']
for path in possible_list:
resp = client.get(path)
print('菜单列表(尝试路径=', path, ') status=', resp.status_code)
print(resp.text)
if resp.status_code == 200:
break
if __name__ == '__main__':
run_menu_tests()
import random
import string
from typing import Dict
from client import ApiClient
def _rand_suffix(n: int = 5) -> str:
import random as _r, string as _s
return ''.join(_r.choice(_s.ascii_lowercase + _s.digits) for _ in range(n))
def run_role_tests(base_url: str = 'http://localhost:8083') -> None:
client = ApiClient(base_url)
# 1) 角色列表
resp = client.get('/api/system/role/list', params={'pageNum': 1, 'pageSize': 5})
print('角色列表 status=', resp.status_code)
print(resp.text)
# 2) 新增角色
new_role: Dict = {
'roleCode': f'test_{_rand_suffix()}',
'roleName': '接口测试角色',
'status': 1,
'menuIds': [] # 如有菜单ID可填充
}
resp = client.post('/api/system/role/add', new_role)
print('新增角色 status=', resp.status_code)
print(resp.text)
role_id = None
try:
lst = client.get('/api/system/role/list', params={'roleCode': new_role['roleCode'], 'pageNum': 1, 'pageSize': 1}).json()
records = ((lst.get('data') or {}).get('records') or [])
if records:
role_id = records[0].get('roleId')
except Exception:
pass
# 3) 编辑角色
if role_id:
edit_body = {
'roleId': role_id,
'roleCode': new_role['roleCode'],
'roleName': '接口测试角色-已修改',
'status': 1,
'menuIds': []
}
resp = client.post('/api/system/role/edit', edit_body)
print('编辑角色 status=', resp.status_code)
print(resp.text)
# 4) 停用角色
resp = client.post('/api/system/role/changeStatus', {'roleId': role_id, 'status': 0})
print('修改角色状态 status=', resp.status_code)
print(resp.text)
# 5) 删除角色
resp = client.delete(f'/api/system/role/{role_id}')
print('删除角色 status=', resp.status_code)
print(resp.text)
if __name__ == '__main__':
run_role_tests()
import random
import string
from typing import Dict
from client import ApiClient
def _rand_suffix(n: int = 6) -> str:
return ''.join(random.choice(string.ascii_lowercase + string.digits) for _ in range(n))
def run_user_tests(base_url: str = 'http://localhost:8083') -> None:
client = ApiClient(base_url)
# 1) 列表查询
resp = client.get('/api/system/user/list', params={'pageNum': 1, 'pageSize': 5})
print('用户列表 status=', resp.status_code)
print(resp.text)
# 2) 新增用户
mock_user: Dict = {
'username': f'test_{_rand_suffix()}',
'password': '123456',
'realName': '接口测试用户',
'phone': '18221643976',
'email': f'test_{_rand_suffix()}@example.com',
'status': 1,
'roleIds': [1] # 根据系统内置角色调整
}
resp = client.post('/api/system/user/add', mock_user)
print('新增用户 status=', resp.status_code)
print(resp.text)
user_id = None
try:
data = resp.json()
if data.get('code') == 200:
# 简化:再拉一次列表找刚才的用户
lst = client.get('/api/system/user/list', params={'username': mock_user['username'], 'pageNum': 1, 'pageSize': 1}).json()
records = ((lst.get('data') or {}).get('records') or [])
if records:
user_id = records[0].get('userId')
except Exception:
pass
# 3) 编辑用户(若拿到了ID)
if user_id:
edit_body = {
'userId': user_id,
'username': mock_user['username'],
'realName': '接口测试用户-已修改',
'phone': mock_user['phone'],
'email': mock_user['email'],
'status': 1,
'roleIds': [1]
}
resp = client.post('/api/system/user/edit', edit_body)
print('编辑用户 status=', resp.status_code)
print(resp.text)
# 4) 重置密码
resp = client.put('/api/system/user/resetPwd', {'userId': user_id, 'newPassword': 'newpass123'})
print('重置密码 status=', resp.status_code)
print(resp.text)
# 5) 停用用户
resp = client.post('/api/system/user/changeStatus', {'userId': user_id, 'status': 0})
print('修改用户状态 status=', resp.status_code)
print(resp.text)
# 6) 删除用户
resp = client.delete(f'/api/system/user/{user_id}')
print('删除用户 status=', resp.status_code)
print(resp.text)
if __name__ == '__main__':
run_user_tests()