08ea5fbe98
添加用户管理视图、API和状态管理文件
655 lines
15 KiB
Python
655 lines
15 KiB
Python
"""
|
||
统一测试工具接口标准
|
||
定义所有测试工具应遵循的统一接口规范
|
||
"""
|
||
|
||
from abc import ABC, abstractmethod
|
||
from typing import Dict, Any, List, Optional, Tuple
|
||
from dataclasses import dataclass
|
||
from enum import Enum
|
||
|
||
|
||
class TestStatus(Enum):
|
||
"""测试状态枚举"""
|
||
PASSED = "passed"
|
||
FAILED = "failed"
|
||
SKIPPED = "skipped"
|
||
RUNNING = "running"
|
||
|
||
|
||
class LogLevel(Enum):
|
||
"""日志级别枚举"""
|
||
DEBUG = "DEBUG"
|
||
INFO = "INFO"
|
||
WARNING = "WARNING"
|
||
ERROR = "ERROR"
|
||
CRITICAL = "CRITICAL"
|
||
|
||
|
||
@dataclass
|
||
class TestConfig:
|
||
"""测试配置数据类"""
|
||
name: str
|
||
version: str
|
||
description: str
|
||
|
||
# API配置
|
||
api_base_url: str
|
||
api_timeout: int
|
||
api_max_retries: int
|
||
|
||
# 认证配置
|
||
auth_enabled: bool
|
||
auth_login_endpoint: str
|
||
auth_username: str
|
||
auth_password: str
|
||
|
||
# 测试配置
|
||
test_parallel: bool
|
||
test_retry_count: int
|
||
|
||
# 报告配置
|
||
report_output_dir: str
|
||
report_formats: List[str]
|
||
report_include_details: bool
|
||
|
||
# 日志配置
|
||
logging_level: str
|
||
logging_file: str
|
||
logging_console: bool
|
||
|
||
|
||
@dataclass
|
||
class TestResult:
|
||
"""测试结果数据类"""
|
||
test_name: str
|
||
test_type: str
|
||
status: TestStatus
|
||
url: str
|
||
method: str
|
||
status_code: int
|
||
response_time: float
|
||
error_message: str
|
||
request_data: Dict[str, Any]
|
||
response_data: Dict[str, Any]
|
||
timestamp: str
|
||
stack_trace: Optional[str] = None
|
||
|
||
def to_dict(self) -> Dict[str, Any]:
|
||
"""转换为字典"""
|
||
return {
|
||
"test_name": self.test_name,
|
||
"test_type": self.test_type,
|
||
"status": self.status.value,
|
||
"url": self.url,
|
||
"method": self.method,
|
||
"status_code": self.status_code,
|
||
"response_time": self.response_time,
|
||
"error_message": self.error_message,
|
||
"request_data": self.request_data,
|
||
"response_data": self.response_data,
|
||
"timestamp": self.timestamp,
|
||
"stack_trace": self.stack_trace
|
||
}
|
||
|
||
|
||
@dataclass
|
||
class TestSummary:
|
||
"""测试摘要数据类"""
|
||
total: int
|
||
passed: int
|
||
failed: int
|
||
skipped: int
|
||
pass_rate: float
|
||
total_time: float
|
||
start_time: str
|
||
end_time: str
|
||
|
||
def to_dict(self) -> Dict[str, Any]:
|
||
"""转换为字典"""
|
||
return {
|
||
"total": self.total,
|
||
"passed": self.passed,
|
||
"failed": self.failed,
|
||
"skipped": self.skipped,
|
||
"pass_rate": self.pass_rate,
|
||
"total_time": self.total_time,
|
||
"start_time": self.start_time,
|
||
"end_time": self.end_time
|
||
}
|
||
|
||
|
||
@dataclass
|
||
class ValidationRule:
|
||
"""验证规则数据类"""
|
||
rule_type: str
|
||
expected_value: Any
|
||
path: Optional[str] = None
|
||
description: Optional[str] = None
|
||
|
||
|
||
class ITestTool(ABC):
|
||
"""测试工具接口"""
|
||
|
||
@abstractmethod
|
||
def get_name(self) -> str:
|
||
"""
|
||
获取测试工具名称
|
||
|
||
Returns:
|
||
工具名称
|
||
"""
|
||
pass
|
||
|
||
@abstractmethod
|
||
def get_version(self) -> str:
|
||
"""
|
||
获取测试工具版本
|
||
|
||
Returns:
|
||
工具版本
|
||
"""
|
||
pass
|
||
|
||
@abstractmethod
|
||
def load_config(self, config_path: str = None) -> None:
|
||
"""
|
||
加载配置
|
||
|
||
Args:
|
||
config_path: 配置文件路径
|
||
"""
|
||
pass
|
||
|
||
@abstractmethod
|
||
def get_config(self) -> TestConfig:
|
||
"""
|
||
获取配置
|
||
|
||
Returns:
|
||
配置对象
|
||
"""
|
||
pass
|
||
|
||
@abstractmethod
|
||
def run_tests(self, test_cases: List[Any] = None) -> Tuple[List[TestResult], TestSummary]:
|
||
"""
|
||
运行测试
|
||
|
||
Args:
|
||
test_cases: 测试用例列表
|
||
|
||
Returns:
|
||
(测试结果列表, 测试摘要)
|
||
"""
|
||
pass
|
||
|
||
@abstractmethod
|
||
def generate_report(self, results: List[TestResult], summary: TestSummary, format: str = "json") -> str:
|
||
"""
|
||
生成测试报告
|
||
|
||
Args:
|
||
results: 测试结果列表
|
||
summary: 测试摘要
|
||
format: 报告格式(json, html, pdf)
|
||
|
||
Returns:
|
||
报告文件路径
|
||
"""
|
||
pass
|
||
|
||
@abstractmethod
|
||
def set_log_level(self, level: LogLevel) -> None:
|
||
"""
|
||
设置日志级别
|
||
|
||
Args:
|
||
level: 日志级别
|
||
"""
|
||
pass
|
||
|
||
@abstractmethod
|
||
def get_logs(self) -> List[str]:
|
||
"""
|
||
获取日志
|
||
|
||
Returns:
|
||
日志列表
|
||
"""
|
||
pass
|
||
|
||
@abstractmethod
|
||
def cleanup(self) -> None:
|
||
"""清理资源"""
|
||
pass
|
||
|
||
|
||
class IAPITester(ITestTool):
|
||
"""API测试工具接口"""
|
||
|
||
@abstractmethod
|
||
def login(self, username: str = None, password: str = None) -> bool:
|
||
"""
|
||
用户登录
|
||
|
||
Args:
|
||
username: 用户名
|
||
password: 密码
|
||
|
||
Returns:
|
||
是否登录成功
|
||
"""
|
||
pass
|
||
|
||
@abstractmethod
|
||
def request(
|
||
self,
|
||
method: str,
|
||
endpoint: str,
|
||
data: Dict[str, Any] = None,
|
||
params: Dict[str, Any] = None,
|
||
headers: Dict[str, str] = None,
|
||
expected_status: int = 200
|
||
) -> TestResult:
|
||
"""
|
||
发送HTTP请求
|
||
|
||
Args:
|
||
method: HTTP方法
|
||
endpoint: API端点
|
||
data: 请求体数据
|
||
params: URL参数
|
||
headers: 请求头
|
||
expected_status: 期望的状态码
|
||
|
||
Returns:
|
||
测试结果
|
||
"""
|
||
pass
|
||
|
||
@abstractmethod
|
||
def validate(self, result: TestResult, rules: List[ValidationRule]) -> TestResult:
|
||
"""
|
||
验证测试结果
|
||
|
||
Args:
|
||
result: 测试结果
|
||
rules: 验证规则列表
|
||
|
||
Returns:
|
||
验证后的测试结果
|
||
"""
|
||
pass
|
||
|
||
|
||
class IE2ETester(ITestTool):
|
||
"""E2E测试工具接口"""
|
||
|
||
@abstractmethod
|
||
def navigate(self, url: str) -> None:
|
||
"""
|
||
导航到指定URL
|
||
|
||
Args:
|
||
url: 目标URL
|
||
"""
|
||
pass
|
||
|
||
@abstractmethod
|
||
def click(self, selector: str) -> None:
|
||
"""
|
||
点击元素
|
||
|
||
Args:
|
||
selector: 元素选择器
|
||
"""
|
||
pass
|
||
|
||
@abstractmethod
|
||
def fill(self, selector: str, value: str) -> None:
|
||
"""
|
||
填写表单字段
|
||
|
||
Args:
|
||
selector: 元素选择器
|
||
value: 填充值
|
||
"""
|
||
pass
|
||
|
||
@abstractmethod
|
||
def wait_for_element(self, selector: str, timeout: int = 5000) -> None:
|
||
"""
|
||
等待元素出现
|
||
|
||
Args:
|
||
selector: 元素选择器
|
||
timeout: 超时时间(毫秒)
|
||
"""
|
||
pass
|
||
|
||
@abstractmethod
|
||
def take_screenshot(self, name: str) -> str:
|
||
"""
|
||
截取屏幕截图
|
||
|
||
Args:
|
||
name: 截图名称
|
||
|
||
Returns:
|
||
截图文件路径
|
||
"""
|
||
pass
|
||
|
||
@abstractmethod
|
||
def expect_visible(self, selector: str, timeout: int = 5000) -> None:
|
||
"""
|
||
期望元素可见
|
||
|
||
Args:
|
||
selector: 元素选择器
|
||
timeout: 超时时间(毫秒)
|
||
"""
|
||
pass
|
||
|
||
@abstractmethod
|
||
def expect_text(self, selector: str, expected_text: str, timeout: int = 5000) -> None:
|
||
"""
|
||
期望元素包含指定文本
|
||
|
||
Args:
|
||
selector: 元素选择器
|
||
expected_text: 期望的文本
|
||
timeout: 超时时间(毫秒)
|
||
"""
|
||
pass
|
||
|
||
|
||
class IValidationEngine(ABC):
|
||
"""验证引擎接口"""
|
||
|
||
@abstractmethod
|
||
def validate_status_code(self, expected: int, actual: int) -> Tuple[bool, str]:
|
||
"""
|
||
验证HTTP状态码
|
||
|
||
Args:
|
||
expected: 期望的状态码
|
||
actual: 实际的状态码
|
||
|
||
Returns:
|
||
(是否通过, 错误消息)
|
||
"""
|
||
pass
|
||
|
||
@abstractmethod
|
||
def validate_response_body(self, expected: Dict[str, Any], actual: Dict[str, Any]) -> Tuple[bool, str]:
|
||
"""
|
||
验证响应体
|
||
|
||
Args:
|
||
expected: 期望的响应体
|
||
actual: 实际的响应体
|
||
|
||
Returns:
|
||
(是否通过, 错误消息)
|
||
"""
|
||
pass
|
||
|
||
@abstractmethod
|
||
def validate_contains(self, expected_value: Any, actual_value: Any) -> Tuple[bool, str]:
|
||
"""
|
||
验证包含关系
|
||
|
||
Args:
|
||
expected_value: 期望包含的值
|
||
actual_value: 实际的值
|
||
|
||
Returns:
|
||
(是否通过, 错误消息)
|
||
"""
|
||
pass
|
||
|
||
@abstractmethod
|
||
def validate_equals(self, expected_value: Any, actual_value: Any) -> Tuple[bool, str]:
|
||
"""
|
||
验证相等关系
|
||
|
||
Args:
|
||
expected_value: 期望的值
|
||
actual_value: 实际的值
|
||
|
||
Returns:
|
||
(是否通过, 错误消息)
|
||
"""
|
||
pass
|
||
|
||
@abstractmethod
|
||
def validate_json_path(self, path: str, expected_value: Any, actual_data: Dict[str, Any]) -> Tuple[bool, str]:
|
||
"""
|
||
验证JSON路径
|
||
|
||
Args:
|
||
path: JSON路径
|
||
expected_value: 期望的值
|
||
actual_data: 实际的数据
|
||
|
||
Returns:
|
||
(是否通过, 错误消息)
|
||
"""
|
||
pass
|
||
|
||
@abstractmethod
|
||
def validate_regex(self, pattern: str, actual_value: str) -> Tuple[bool, str]:
|
||
"""
|
||
验证正则表达式
|
||
|
||
Args:
|
||
pattern: 正则表达式模式
|
||
actual_value: 实际的值
|
||
|
||
Returns:
|
||
(是否通过, 错误消息)
|
||
"""
|
||
pass
|
||
|
||
@abstractmethod
|
||
def validate_header(self, expected_header: Dict[str, str], actual_headers: Dict[str, str]) -> Tuple[bool, str]:
|
||
"""
|
||
验证响应头
|
||
|
||
Args:
|
||
expected_header: 期望的响应头
|
||
actual_headers: 实际的响应头
|
||
|
||
Returns:
|
||
(是否通过, 错误消息)
|
||
"""
|
||
pass
|
||
|
||
@abstractmethod
|
||
def validate_response_time(self, expected_max_time: float, actual_time: float) -> Tuple[bool, str]:
|
||
"""
|
||
验证响应时间
|
||
|
||
Args:
|
||
expected_max_time: 期望的最大响应时间(毫秒)
|
||
actual_time: 实际的响应时间(毫秒)
|
||
|
||
Returns:
|
||
(是否通过, 错误消息)
|
||
"""
|
||
pass
|
||
|
||
@abstractmethod
|
||
def validate_schema(self, expected_schema: Dict[str, Any], actual_data: Dict[str, Any]) -> Tuple[bool, str]:
|
||
"""
|
||
验证数据结构
|
||
|
||
Args:
|
||
expected_schema: 期望的结构
|
||
actual_data: 实际的数据
|
||
|
||
Returns:
|
||
(是否通过, 错误消息)
|
||
"""
|
||
pass
|
||
|
||
|
||
class IReportGenerator(ABC):
|
||
"""报告生成器接口"""
|
||
|
||
@abstractmethod
|
||
def generate_json_report(self, results: List[TestResult], summary: TestSummary, filename: str = None) -> str:
|
||
"""
|
||
生成JSON格式报告
|
||
|
||
Args:
|
||
results: 测试结果列表
|
||
summary: 测试摘要
|
||
filename: 报告文件名
|
||
|
||
Returns:
|
||
报告文件路径
|
||
"""
|
||
pass
|
||
|
||
@abstractmethod
|
||
def generate_html_report(self, results: List[TestResult], summary: TestSummary, filename: str = None) -> str:
|
||
"""
|
||
生成HTML格式报告
|
||
|
||
Args:
|
||
results: 测试结果列表
|
||
summary: 测试摘要
|
||
filename: 报告文件名
|
||
|
||
Returns:
|
||
报告文件路径
|
||
"""
|
||
pass
|
||
|
||
@abstractmethod
|
||
def generate_pdf_report(self, results: List[TestResult], summary: TestSummary, filename: str = None) -> str:
|
||
"""
|
||
生成PDF格式报告
|
||
|
||
Args:
|
||
results: 测试结果列表
|
||
summary: 测试摘要
|
||
filename: 报告文件名
|
||
|
||
Returns:
|
||
报告文件路径
|
||
"""
|
||
pass
|
||
|
||
|
||
class ILogger(ABC):
|
||
"""日志记录器接口"""
|
||
|
||
@abstractmethod
|
||
def debug(self, message: str) -> None:
|
||
"""记录调试信息"""
|
||
pass
|
||
|
||
@abstractmethod
|
||
def info(self, message: str) -> None:
|
||
"""记录信息"""
|
||
pass
|
||
|
||
@abstractmethod
|
||
def warning(self, message: str) -> None:
|
||
"""记录警告"""
|
||
pass
|
||
|
||
@abstractmethod
|
||
def error(self, message: str) -> None:
|
||
"""记录错误"""
|
||
pass
|
||
|
||
@abstractmethod
|
||
def critical(self, message: str) -> None:
|
||
"""记录严重错误"""
|
||
pass
|
||
|
||
@abstractmethod
|
||
def exception(self, message: str) -> None:
|
||
"""记录异常信息"""
|
||
pass
|
||
|
||
@abstractmethod
|
||
def set_level(self, level: LogLevel) -> None:
|
||
"""
|
||
设置日志级别
|
||
|
||
Args:
|
||
level: 日志级别
|
||
"""
|
||
pass
|
||
|
||
@abstractmethod
|
||
def get_logs(self) -> List[str]:
|
||
"""
|
||
获取日志
|
||
|
||
Returns:
|
||
日志列表
|
||
"""
|
||
pass
|
||
|
||
|
||
class ITestDataGenerator(ABC):
|
||
"""测试数据生成器接口"""
|
||
|
||
@abstractmethod
|
||
def generate_user_data(self, overrides: Dict[str, Any] = None) -> Dict[str, Any]:
|
||
"""
|
||
生成用户数据
|
||
|
||
Args:
|
||
overrides: 覆盖的默认值
|
||
|
||
Returns:
|
||
用户数据
|
||
"""
|
||
pass
|
||
|
||
@abstractmethod
|
||
def generate_role_data(self, overrides: Dict[str, Any] = None) -> Dict[str, Any]:
|
||
"""
|
||
生成角色数据
|
||
|
||
Args:
|
||
overrides: 覆盖的默认值
|
||
|
||
Returns:
|
||
角色数据
|
||
"""
|
||
pass
|
||
|
||
@abstractmethod
|
||
def generate_menu_data(self, overrides: Dict[str, Any] = None) -> Dict[str, Any]:
|
||
"""
|
||
生成菜单数据
|
||
|
||
Args:
|
||
overrides: 覆盖的默认值
|
||
|
||
Returns:
|
||
菜单数据
|
||
"""
|
||
pass
|
||
|
||
@abstractmethod
|
||
def generate_permission_data(self, overrides: Dict[str, Any] = None) -> Dict[str, Any]:
|
||
"""
|
||
生成权限数据
|
||
|
||
Args:
|
||
overrides: 覆盖的默认值
|
||
|
||
Returns:
|
||
权限数据
|
||
"""
|
||
pass |