refactor(test): 重构测试套件结构并优化测试配置
feat(test-suite): 新增测试套件模块,包含API测试客户端和测试配置 fix(api): 修复数据库实体和仓库的删除操作返回值 style(api): 统一数据库表名和字段命名 perf(api): 添加缓存注解提升配置查询性能 test(api): 添加H2测试数据库配置支持 chore: 清理旧的测试文件和脚本
This commit is contained in:
@@ -0,0 +1 @@
|
||||
"""API模块"""
|
||||
@@ -0,0 +1,72 @@
|
||||
"""
|
||||
审计日志 API 客户端
|
||||
"""
|
||||
|
||||
from httpx import AsyncClient
|
||||
|
||||
|
||||
class AuditLogAPI:
|
||||
"""审计日志 API 客户端"""
|
||||
|
||||
def __init__(self, client: AsyncClient):
|
||||
self.client = client
|
||||
|
||||
async def get_login_log_list(self):
|
||||
"""获取登录日志列表"""
|
||||
return await self.client.get('/api/logs/login')
|
||||
|
||||
async def get_login_log_by_id(self, log_id):
|
||||
"""根据ID获取登录日志"""
|
||||
return await self.client.get(f'/api/logs/login/{log_id}')
|
||||
|
||||
async def get_exception_log_list(self):
|
||||
"""获取异常日志列表"""
|
||||
return await self.client.get('/api/logs/exception')
|
||||
|
||||
async def get_exception_log_by_id(self, log_id):
|
||||
"""根据ID获取异常日志"""
|
||||
return await self.client.get(f'/api/logs/exception/{log_id}')
|
||||
|
||||
async def get_operation_log_list(self):
|
||||
"""获取操作日志列表"""
|
||||
return await self.client.get('/api/logs/operation')
|
||||
|
||||
async def get_operation_log_by_id(self, log_id):
|
||||
"""根据ID获取操作日志"""
|
||||
return await self.client.get(f'/api/logs/operation/{log_id}')
|
||||
|
||||
async def get_login_logs(self, page: int = 0, size: int = 10):
|
||||
"""分页获取登录日志"""
|
||||
return await self.client.get(f'/api/logs/login?page={page}&size={size}')
|
||||
|
||||
async def get_exception_logs(self, page: int = 0, size: int = 10):
|
||||
"""分页获取异常日志"""
|
||||
return await self.client.get(f'/api/logs/exception?page={page}&size={size}')
|
||||
|
||||
async def get_operation_logs(self, page: int = 0, size: int = 10, **kwargs):
|
||||
"""分页获取操作日志,支持筛选参数"""
|
||||
params = {'page': page, 'size': size}
|
||||
params.update(kwargs)
|
||||
return await self.client.get('/api/logs/operation/page', params=params)
|
||||
|
||||
async def create_login_log(self, data):
|
||||
"""创建登录日志"""
|
||||
return await self.client.post('/api/logs/login', json=data)
|
||||
|
||||
async def create_exception_log(self, data):
|
||||
"""创建异常日志"""
|
||||
return await self.client.post('/api/logs/exception', json=data)
|
||||
|
||||
async def create_operation_log(self, data):
|
||||
"""创建操作日志"""
|
||||
return await self.client.post('/api/logs/operation', json=data)
|
||||
|
||||
|
||||
class SysLogAPI(AuditLogAPI):
|
||||
"""系统日志 API (别名)"""
|
||||
pass
|
||||
|
||||
|
||||
class AuditAPI(AuditLogAPI):
|
||||
"""审计 API (别名)"""
|
||||
pass
|
||||
@@ -0,0 +1,31 @@
|
||||
"""
|
||||
认证 API 客户端
|
||||
"""
|
||||
|
||||
from httpx import AsyncClient
|
||||
|
||||
|
||||
class AuthAPI:
|
||||
"""认证 API 客户端"""
|
||||
|
||||
def __init__(self, client: AsyncClient):
|
||||
self.client = client
|
||||
|
||||
async def login(self, username: str, password: str):
|
||||
"""登录"""
|
||||
return await self.client.post('/api/auth/login', json={
|
||||
'username': username,
|
||||
'password': password
|
||||
})
|
||||
|
||||
async def register(self, username: str, password: str, email: str):
|
||||
"""注册"""
|
||||
return await self.client.post('/api/auth/register', json={
|
||||
'username': username,
|
||||
'password': password,
|
||||
'email': email
|
||||
})
|
||||
|
||||
async def logout(self):
|
||||
"""登出"""
|
||||
return await self.client.post('/api/auth/logout')
|
||||
@@ -0,0 +1,225 @@
|
||||
# API 集成测试 - 基础API客户端
|
||||
import pytest
|
||||
import requests
|
||||
import time
|
||||
import os
|
||||
from typing import Optional, Dict, Any, Union
|
||||
from requests.adapters import HTTPAdapter, Retry
|
||||
from dotenv import load_dotenv
|
||||
import httpx
|
||||
|
||||
# 加载环境变量
|
||||
load_dotenv()
|
||||
|
||||
|
||||
class BaseAPIClient:
|
||||
"""基础 API 客户端,提供通用的 HTTP 请求方法"""
|
||||
|
||||
def __init__(self, base_url: Optional[str] = None, timeout: int = 30):
|
||||
self.base_url = base_url or os.getenv('BASE_URL', 'http://localhost:8084')
|
||||
self.timeout = timeout
|
||||
self.session = requests.Session()
|
||||
self.token: Optional[str] = None
|
||||
self.user_id: Optional[int] = None
|
||||
|
||||
# 配置重试策略
|
||||
retries = Retry(
|
||||
total=3,
|
||||
backoff_factor=0.1,
|
||||
status_forcelist=[500, 502, 503, 504]
|
||||
)
|
||||
self.session.mount('http', HTTPAdapter(max_retries=retries))
|
||||
self.session.mount('https', HTTPAdapter(max_retries=retries))
|
||||
|
||||
def login(self, username: str, password: str) -> bool:
|
||||
"""登录并获取 Token"""
|
||||
response = self.post(
|
||||
'/api/auth/login',
|
||||
json={'username': username, 'password': password},
|
||||
include_auth=False
|
||||
)
|
||||
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
self.token = data.get('token')
|
||||
self.user_id = data.get('userId')
|
||||
print(f"✅ 登录成功: {username} (User ID: {self.user_id})")
|
||||
return True
|
||||
else:
|
||||
print(f"❌ 登录失败: {response.status_code}")
|
||||
return False
|
||||
|
||||
def _build_url(self, path: str) -> str:
|
||||
"""构建完整 URL"""
|
||||
if path.startswith('http'):
|
||||
return path
|
||||
return f"{self.base_url}{path}"
|
||||
|
||||
def _get_headers(self, include_auth: bool = True) -> Dict[str, str]:
|
||||
"""获取请求头"""
|
||||
headers = {
|
||||
'Content-Type': 'application/json',
|
||||
'Accept': 'application/json'
|
||||
}
|
||||
|
||||
if include_auth and self.token:
|
||||
headers['Authorization'] = f"Bearer {self.token}"
|
||||
|
||||
return headers
|
||||
|
||||
def get(self, path: str, params: Optional[Dict] = None, include_auth: bool = True) -> requests.Response:
|
||||
"""GET 请求"""
|
||||
url = self._build_url(path)
|
||||
headers = self._get_headers(include_auth)
|
||||
|
||||
response = self.session.get(
|
||||
url,
|
||||
headers=headers,
|
||||
params=params,
|
||||
timeout=self.timeout
|
||||
)
|
||||
|
||||
return response
|
||||
|
||||
def post(self, path: str, data: Optional[Dict] = None, json: Optional[Dict] = None,
|
||||
include_auth: bool = True) -> requests.Response:
|
||||
"""POST 请求"""
|
||||
url = self._build_url(path)
|
||||
headers = self._get_headers(include_auth)
|
||||
|
||||
response = self.session.post(
|
||||
url,
|
||||
headers=headers,
|
||||
data=data,
|
||||
json=json,
|
||||
timeout=self.timeout
|
||||
)
|
||||
|
||||
return response
|
||||
|
||||
def put(self, path: str, data: Optional[Dict] = None, json: Optional[Dict] = None,
|
||||
include_auth: bool = True) -> requests.Response:
|
||||
"""PUT 请求"""
|
||||
url = self._build_url(path)
|
||||
headers = self._get_headers(include_auth)
|
||||
|
||||
response = self.session.put(
|
||||
url,
|
||||
headers=headers,
|
||||
data=data,
|
||||
json=json,
|
||||
timeout=self.timeout
|
||||
)
|
||||
|
||||
return response
|
||||
|
||||
def delete(self, path: str, include_auth: bool = True) -> requests.Response:
|
||||
"""DELETE 请求"""
|
||||
url = self._build_url(path)
|
||||
headers = self._get_headers(include_auth)
|
||||
|
||||
response = self.session.delete(
|
||||
url,
|
||||
headers=headers,
|
||||
timeout=self.timeout
|
||||
)
|
||||
|
||||
return response
|
||||
|
||||
def cleanup_resource(self, resource_type: str, resource_id: int) -> bool:
|
||||
"""清理测试资源"""
|
||||
try:
|
||||
response = self.delete(f'/api/{resource_type}/{resource_id}')
|
||||
return response.status_code == 200
|
||||
except Exception as e:
|
||||
print(f"清理资源失败: {e}")
|
||||
return False
|
||||
|
||||
|
||||
class APIFixture:
|
||||
"""API 测试固定装置,提供测试数据管理"""
|
||||
|
||||
def __init__(self, api_client: BaseAPIClient):
|
||||
self.api_client = api_client
|
||||
self.created_users = []
|
||||
self.created_roles = []
|
||||
self.created_menus = []
|
||||
self.created_configs = []
|
||||
self.created_dicts = []
|
||||
|
||||
def cleanup(self):
|
||||
"""清理所有创建的测试数据"""
|
||||
print("\n🧹 清理测试数据...")
|
||||
|
||||
# 清理用户
|
||||
for user_id in self.created_users:
|
||||
self.api_client.cleanup_resource('users', user_id)
|
||||
self.created_users.clear()
|
||||
|
||||
# 清理角色
|
||||
for role_id in self.created_roles:
|
||||
self.api_client.cleanup_resource('roles', role_id)
|
||||
self.created_roles.clear()
|
||||
|
||||
# 清理菜单
|
||||
for menu_id in self.created_menus:
|
||||
self.api_client.cleanup_resource('menus', menu_id)
|
||||
self.created_menus.clear()
|
||||
|
||||
# 清理配置
|
||||
for config_id in self.created_configs:
|
||||
self.api_client.cleanup_resource('config', config_id)
|
||||
self.created_configs.clear()
|
||||
|
||||
# 清理字典
|
||||
for dict_id in self.created_dicts:
|
||||
self.api_client.cleanup_resource('dict', dict_id)
|
||||
self.created_dicts.clear()
|
||||
|
||||
print("✅ 测试数据清理完成")
|
||||
|
||||
|
||||
class AsyncAPIClient:
|
||||
"""异步 API 客户端,使用 httpx"""
|
||||
|
||||
def __init__(self, client: httpx.AsyncClient):
|
||||
self.client = client
|
||||
self.token: Optional[str] = None
|
||||
self.user_id: Optional[int] = None
|
||||
|
||||
def set_auth(self, token: str, user_id: int = None):
|
||||
"""设置认证信息"""
|
||||
self.token = token
|
||||
self.user_id = user_id
|
||||
self.client.headers.update({'Authorization': f'Bearer {token}'})
|
||||
|
||||
async def login(self, username: str, password: str) -> httpx.Response:
|
||||
"""登录并获取 Token"""
|
||||
response = await self.client.post(
|
||||
'/api/auth/login',
|
||||
json={'username': username, 'password': password}
|
||||
)
|
||||
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
self.token = data.get('token')
|
||||
self.user_id = data.get('userId')
|
||||
print(f"✅ 登录成功: {username} (User ID: {self.user_id})")
|
||||
|
||||
return response
|
||||
|
||||
async def get(self, path: str, params: Optional[Dict] = None) -> httpx.Response:
|
||||
"""GET 请求"""
|
||||
return await self.client.get(path, params=params)
|
||||
|
||||
async def post(self, path: str, json: Optional[Dict] = None) -> httpx.Response:
|
||||
"""POST 请求"""
|
||||
return await self.client.post(path, json=json)
|
||||
|
||||
async def put(self, path: str, json: Optional[Dict] = None) -> httpx.Response:
|
||||
"""PUT 请求"""
|
||||
return await self.client.put(path, json=json)
|
||||
|
||||
async def delete(self, path: str) -> httpx.Response:
|
||||
"""DELETE 请求"""
|
||||
return await self.client.delete(path)
|
||||
@@ -0,0 +1,45 @@
|
||||
"""
|
||||
系统配置 API 客户端
|
||||
"""
|
||||
|
||||
from httpx import AsyncClient
|
||||
|
||||
|
||||
class ConfigAPI:
|
||||
"""系统配置 API 客户端"""
|
||||
|
||||
def __init__(self, client: AsyncClient):
|
||||
self.client = client
|
||||
|
||||
async def get_config_list(self):
|
||||
"""获取配置列表"""
|
||||
return await self.client.get('/api/config')
|
||||
|
||||
async def get_config_by_id(self, config_id):
|
||||
"""根据ID获取配置"""
|
||||
return await self.client.get(f'/api/config/{config_id}')
|
||||
|
||||
async def get_config_by_key(self, config_key):
|
||||
"""根据key获取配置"""
|
||||
return await self.client.get(f'/api/config/key/{config_key}')
|
||||
|
||||
async def create(self, config_data):
|
||||
"""创建配置"""
|
||||
return await self.client.post('/api/config', json=config_data)
|
||||
|
||||
async def update(self, config_id, config_data):
|
||||
"""更新配置"""
|
||||
return await self.client.put(f'/api/config/{config_id}', json=config_data)
|
||||
|
||||
async def delete(self, config_id):
|
||||
"""删除配置"""
|
||||
return await self.client.delete(f'/api/config/{config_id}')
|
||||
|
||||
async def get_all(self):
|
||||
"""获取所有配置"""
|
||||
return await self.client.get('/api/config')
|
||||
|
||||
|
||||
class SysConfigAPI(ConfigAPI):
|
||||
"""系统配置 API (别名)"""
|
||||
pass
|
||||
@@ -0,0 +1,64 @@
|
||||
"""
|
||||
字典管理 API 客户端
|
||||
"""
|
||||
|
||||
from httpx import AsyncClient
|
||||
|
||||
|
||||
class DictTypeAPI:
|
||||
"""字典类型 API 客户端"""
|
||||
|
||||
def __init__(self, client: AsyncClient):
|
||||
self.client = client
|
||||
|
||||
async def get_type_list(self, page: int = 0, size: int = 10):
|
||||
"""获取字典类型列表"""
|
||||
return await self.client.get(f'/api/dict/types?page={page}&size={size}')
|
||||
|
||||
async def get_type_by_id(self, dict_type_id: int):
|
||||
"""根据ID获取字典类型"""
|
||||
return await self.client.get(f'/api/dict/types/{dict_type_id}')
|
||||
|
||||
async def create(self, dict_type_data):
|
||||
"""创建字典类型"""
|
||||
return await self.client.post('/api/dict/types', json=dict_type_data)
|
||||
|
||||
async def update(self, dict_type_id: int, dict_type_data):
|
||||
"""更新字典类型"""
|
||||
return await self.client.put(f'/api/dict/types/{dict_type_id}', json=dict_type_data)
|
||||
|
||||
async def delete(self, dict_type_id: int):
|
||||
"""删除字典类型"""
|
||||
return await self.client.delete(f'/api/dict/types/{dict_type_id}')
|
||||
|
||||
|
||||
class DictDataAPI:
|
||||
"""字典数据 API 客户端"""
|
||||
|
||||
def __init__(self, client: AsyncClient):
|
||||
self.client = client
|
||||
|
||||
async def get_dict_list(self, page: int = 0, size: int = 10):
|
||||
"""获取字典数据列表"""
|
||||
return await self.client.get(f'/api/dict?page={page}&size={size}')
|
||||
|
||||
async def get_dict_by_id(self, dict_id: int):
|
||||
"""根据ID获取字典数据"""
|
||||
return await self.client.get(f'/api/dict/{dict_id}')
|
||||
|
||||
async def create(self, dict_data):
|
||||
"""创建字典数据"""
|
||||
return await self.client.post('/api/dict', json=dict_data)
|
||||
|
||||
async def update(self, dict_id: int, dict_data):
|
||||
"""更新字典数据"""
|
||||
return await self.client.put(f'/api/dict/{dict_id}', json=dict_data)
|
||||
|
||||
async def delete(self, dict_id: int):
|
||||
"""删除字典数据"""
|
||||
return await self.client.delete(f'/api/dict/{dict_id}')
|
||||
|
||||
|
||||
class DictAPI(DictTypeAPI, DictDataAPI):
|
||||
"""字典管理 API (组合)"""
|
||||
pass
|
||||
@@ -0,0 +1,32 @@
|
||||
"""
|
||||
字典管理 API 客户端
|
||||
"""
|
||||
|
||||
from httpx import AsyncClient
|
||||
|
||||
|
||||
class DictionaryAPI:
|
||||
"""字典管理 API 客户端"""
|
||||
|
||||
def __init__(self, client: AsyncClient):
|
||||
self.client = client
|
||||
|
||||
async def get_dictionary_list(self):
|
||||
"""获取字典列表"""
|
||||
return await self.client.get('/api/dictionary')
|
||||
|
||||
async def get_dictionary_by_id(self, dictionary_id):
|
||||
"""根据ID获取字典"""
|
||||
return await self.client.get(f'/api/dictionary/{dictionary_id}')
|
||||
|
||||
async def create_dictionary(self, dictionary_data):
|
||||
"""创建字典"""
|
||||
return await self.client.post('/api/dictionary', json=dictionary_data)
|
||||
|
||||
async def update_dictionary(self, dictionary_id, dictionary_data):
|
||||
"""更新字典"""
|
||||
return await self.client.put(f'/api/dictionary/{dictionary_id}', json=dictionary_data)
|
||||
|
||||
async def delete_dictionary(self, dictionary_id):
|
||||
"""删除字典"""
|
||||
return await self.client.delete(f'/api/dictionary/{dictionary_id}')
|
||||
@@ -0,0 +1,57 @@
|
||||
"""
|
||||
文件管理 API 客户端
|
||||
"""
|
||||
|
||||
from httpx import AsyncClient
|
||||
import io
|
||||
|
||||
|
||||
class FileAPI:
|
||||
"""文件管理 API 客户端"""
|
||||
|
||||
def __init__(self, client: AsyncClient):
|
||||
self.client = client
|
||||
|
||||
async def get_file_list(self):
|
||||
"""获取文件列表"""
|
||||
return await self.client.get('/api/files')
|
||||
|
||||
async def get_file_by_id(self, file_id):
|
||||
"""根据ID获取文件"""
|
||||
return await self.client.get(f'/api/files/{file_id}')
|
||||
|
||||
async def upload(self, file_path, upload_user):
|
||||
"""上传文件"""
|
||||
with open(file_path, 'rb') as f:
|
||||
return await self.client.post('/api/files/upload', json={'file': file_path, 'uploadUser': upload_user})
|
||||
|
||||
async def upload_file(self, file_content, filename, upload_user="test_user"):
|
||||
"""上传文件(内存方式)"""
|
||||
files = {'file': (filename, file_content, 'text/plain')}
|
||||
headers = {'X-Username': upload_user}
|
||||
return await self.client.post('/api/files/upload', files=files, headers=headers)
|
||||
|
||||
async def download(self, file_id):
|
||||
"""下载文件"""
|
||||
return await self.client.get(f'/api/files/{file_id}/download')
|
||||
|
||||
async def delete(self, file_id):
|
||||
"""删除文件"""
|
||||
return await self.client.delete(f'/api/files/{file_id}')
|
||||
|
||||
async def get_file_info(self, file_id):
|
||||
"""获取文件信息(别名)"""
|
||||
return await self.get_file_by_id(file_id)
|
||||
|
||||
async def download_file(self, file_id):
|
||||
"""下载文件(别名)"""
|
||||
return await self.download(file_id)
|
||||
|
||||
async def delete_file(self, file_id):
|
||||
"""删除文件(别名)"""
|
||||
return await self.delete(file_id)
|
||||
|
||||
|
||||
class SysFileAPI(FileAPI):
|
||||
"""系统文件 API (别名)"""
|
||||
pass
|
||||
@@ -0,0 +1,20 @@
|
||||
# API 集成测试 - 登录测试
|
||||
import pytest
|
||||
import sys
|
||||
import os
|
||||
|
||||
# 添加当前目录到Python路径
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
from api.base_api import BaseAPIClient
|
||||
|
||||
|
||||
class TestLoginAPI:
|
||||
"""登录 API 测试"""
|
||||
|
||||
def test_login_success(self):
|
||||
"""测试登录成功"""
|
||||
client = BaseAPIClient(base_url='http://localhost:8084')
|
||||
result = client.login('admin', 'admin123')
|
||||
assert result, "登录应该成功"
|
||||
assert client.token is not None, "Token 应该被设置"
|
||||
@@ -0,0 +1,44 @@
|
||||
"""
|
||||
菜单管理 API 客户端
|
||||
"""
|
||||
|
||||
from httpx import AsyncClient
|
||||
|
||||
|
||||
class MenuAPI:
|
||||
"""菜单管理 API 客户端"""
|
||||
|
||||
def __init__(self, client: AsyncClient):
|
||||
self.client = client
|
||||
|
||||
async def get_menu_list(self):
|
||||
"""获取菜单列表"""
|
||||
return await self.client.get('/api/menus')
|
||||
|
||||
async def get_menu_tree(self):
|
||||
"""获取菜单树"""
|
||||
return await self.client.get('/api/menus/tree')
|
||||
|
||||
async def get_menu_by_id(self, menu_id):
|
||||
"""根据ID获取菜单"""
|
||||
return await self.client.get(f'/api/menus/{menu_id}')
|
||||
|
||||
async def create_menu(self, menu_data):
|
||||
"""创建菜单"""
|
||||
return await self.client.post('/api/menus', json=menu_data)
|
||||
|
||||
async def update_menu(self, menu_id, menu_data):
|
||||
"""更新菜单"""
|
||||
return await self.client.put(f'/api/menus/{menu_id}', json=menu_data)
|
||||
|
||||
async def delete_menu(self, menu_id):
|
||||
"""删除菜单"""
|
||||
return await self.client.delete(f'/api/menus/{menu_id}')
|
||||
|
||||
async def get_user_menus(self, user_id):
|
||||
"""获取用户菜单"""
|
||||
return await self.client.get(f'/api/menus/user/{user_id}')
|
||||
|
||||
async def get_user_menus_by_role(self, role_id):
|
||||
"""获取角色菜单"""
|
||||
return await self.client.get(f'/api/menus/role/{role_id}')
|
||||
@@ -0,0 +1,50 @@
|
||||
"""
|
||||
通知公告 API 客户端
|
||||
"""
|
||||
|
||||
from httpx import AsyncClient
|
||||
|
||||
|
||||
class NoticeAPI:
|
||||
"""通知公告 API 客户端"""
|
||||
|
||||
def __init__(self, client: AsyncClient):
|
||||
self.client = client
|
||||
|
||||
async def get_notice_list(self):
|
||||
"""获取公告列表"""
|
||||
return await self.client.get('/api/notices')
|
||||
|
||||
async def get_notice_by_id(self, notice_id):
|
||||
"""根据ID获取公告"""
|
||||
return await self.client.get(f'/api/notices/{notice_id}')
|
||||
|
||||
async def create(self, notice_data):
|
||||
"""创建公告"""
|
||||
return await self.client.post('/api/notices', json=notice_data)
|
||||
|
||||
async def update(self, notice_id, notice_data):
|
||||
"""更新公告"""
|
||||
return await self.client.put(f'/api/notices/{notice_id}', json=notice_data)
|
||||
|
||||
async def delete(self, notice_id):
|
||||
"""删除公告"""
|
||||
return await self.client.delete(f'/api/notices/{notice_id}')
|
||||
|
||||
async def get_list(self, page: int = 0, size: int = 10):
|
||||
"""分页获取公告列表"""
|
||||
return await self.client.get(f'/api/notices?page={page}&size={size}')
|
||||
|
||||
async def get_all(self):
|
||||
"""获取所有公告"""
|
||||
return await self.client.get('/api/notices/all')
|
||||
|
||||
|
||||
class SysNoticeAPI(NoticeAPI):
|
||||
"""系统公告 API (别名)"""
|
||||
pass
|
||||
|
||||
|
||||
class SysMessageAPI(NoticeAPI):
|
||||
"""系统消息 API (别名)"""
|
||||
pass
|
||||
@@ -0,0 +1,48 @@
|
||||
"""
|
||||
角色管理 API 客户端
|
||||
"""
|
||||
|
||||
from httpx import AsyncClient
|
||||
|
||||
|
||||
class RoleAPI:
|
||||
"""角色管理 API 客户端"""
|
||||
|
||||
def __init__(self, client: AsyncClient):
|
||||
self.client = client
|
||||
|
||||
async def get_role_list(self):
|
||||
"""获取角色列表"""
|
||||
return await self.client.get('/api/roles')
|
||||
|
||||
async def get_role_by_id(self, role_id):
|
||||
"""根据ID获取角色"""
|
||||
return await self.client.get(f'/api/roles/{role_id}')
|
||||
|
||||
async def create_role(self, role_data):
|
||||
"""创建角色"""
|
||||
return await self.client.post('/api/roles', json=role_data)
|
||||
|
||||
async def update_role(self, role_id, role_data):
|
||||
"""更新角色"""
|
||||
return await self.client.put(f'/api/roles/{role_id}', json=role_data)
|
||||
|
||||
async def delete_role(self, role_id):
|
||||
"""删除角色"""
|
||||
return await self.client.delete(f'/api/roles/{role_id}')
|
||||
|
||||
async def get_role_permissions(self, role_id):
|
||||
"""获取角色权限"""
|
||||
return await self.client.get(f'/api/roles/{role_id}/permissions')
|
||||
|
||||
async def assign_permissions(self, role_id, permission_ids):
|
||||
"""分配权限"""
|
||||
return await self.client.post(f'/api/roles/{role_id}/permissions', json={"permissionIds": permission_ids})
|
||||
|
||||
async def assign_menus(self, role_id, menu_ids):
|
||||
"""分配菜单权限(权限分配的别名)"""
|
||||
return await self.assign_permissions(role_id, menu_ids)
|
||||
|
||||
async def get_user_menus_by_role(self, role_id):
|
||||
"""获取角色菜单(别名方法)"""
|
||||
return await self.client.get(f'/api/menus/role/{role_id}')
|
||||
@@ -0,0 +1,39 @@
|
||||
# API 集成测试 - UAT场景测试
|
||||
import pytest
|
||||
import sys
|
||||
import os
|
||||
|
||||
# 添加当前目录到Python路径
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
from api.base_api import BaseAPIClient
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def api_client():
|
||||
"""API 客户端 fixture"""
|
||||
client = BaseAPIClient(base_url='http://localhost:8084')
|
||||
client.login('admin', 'admin123')
|
||||
yield client
|
||||
|
||||
|
||||
class TestUATScenario:
|
||||
"""UAT 场景测试"""
|
||||
|
||||
def test_complete_user_workflow(self, api_client: BaseAPIClient):
|
||||
"""测试完整用户工作流"""
|
||||
# 1. 创建用户
|
||||
response = api_client.post(
|
||||
'/api/users',
|
||||
json={
|
||||
'username': 'uat_test_user',
|
||||
'email': 'uat@test.com',
|
||||
'password': 'uat123',
|
||||
'nickname': 'UAT测试用户'
|
||||
}
|
||||
)
|
||||
assert response.status_code == 201, "创建用户应该成功"
|
||||
|
||||
# 2. 获取用户列表
|
||||
response = api_client.get('/api/users')
|
||||
assert response.status_code == 200, "获取用户列表应该成功"
|
||||
@@ -0,0 +1,50 @@
|
||||
"""
|
||||
用户管理 API 客户端
|
||||
"""
|
||||
|
||||
from httpx import AsyncClient
|
||||
|
||||
|
||||
class UserAPI:
|
||||
"""用户管理 API 客户端"""
|
||||
|
||||
def __init__(self, client: AsyncClient):
|
||||
self.client = client
|
||||
|
||||
async def get_user_list(self):
|
||||
"""获取用户列表"""
|
||||
return await self.client.get('/api/users')
|
||||
|
||||
async def get_users_by_page(self, page: int = 0, size: int = 10, **kwargs):
|
||||
"""分页获取用户列表,支持搜索和排序"""
|
||||
params = {'page': page, 'size': size}
|
||||
params.update(kwargs)
|
||||
return await self.client.get('/api/users', params=params)
|
||||
|
||||
async def create_user(self, user_data):
|
||||
"""创建用户"""
|
||||
return await self.client.post('/api/users', json=user_data)
|
||||
|
||||
async def get_user_by_id(self, user_id):
|
||||
"""根据ID获取用户"""
|
||||
return await self.client.get(f'/api/users/{user_id}')
|
||||
|
||||
async def update_user(self, user_id, user_data):
|
||||
"""更新用户"""
|
||||
return await self.client.put(f'/api/users/{user_id}', json=user_data)
|
||||
|
||||
async def delete_user(self, user_id):
|
||||
"""删除用户"""
|
||||
return await self.client.delete(f'/api/users/{user_id}')
|
||||
|
||||
async def get_user_profile(self):
|
||||
"""获取当前用户资料(调用get_user_by_id,使用token中的userId)"""
|
||||
return await self.client.get('/api/users/profile')
|
||||
|
||||
async def update_user_profile(self, profile_data):
|
||||
"""更新当前用户资料(调用update_user,使用token中的userId)"""
|
||||
return await self.client.put('/api/users/profile', json=profile_data)
|
||||
|
||||
async def assign_roles(self, user_id, role_ids):
|
||||
"""为用户分配角色"""
|
||||
return await self.client.post(f'/api/users/{user_id}/roles', json=role_ids)
|
||||
Reference in New Issue
Block a user