Files
everything-is-suitable/everything-is-suitable-test/test-tools/core/validation.py
T
张翔 08ea5fbe98 feat(admin): 添加用户管理相关文件
添加用户管理视图、API和状态管理文件
2026-03-28 14:37:29 +08:00

300 lines
11 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
测试验证引擎模块
"""
from typing import Dict, Any, Tuple, Optional
import re
import json
from datetime import datetime
class ValidationEngine:
"""测试验证引擎"""
@staticmethod
def validate_status_code(expected: int, actual: int) -> Tuple[bool, str]:
"""
验证HTTP状态码
Args:
expected: 期望的状态码
actual: 实际的状态码
Returns:
(是否通过, 错误消息)
"""
if expected == actual:
return True, ""
return False, f"期望状态码{expected},实际{actual}"
@staticmethod
def validate_response_body(expected: Dict[str, Any], actual: Dict[str, Any]) -> Tuple[bool, str]:
"""
验证响应体
Args:
expected: 期望的响应体
actual: 实际的响应体
Returns:
(是否通过, 错误消息)
"""
if expected == actual:
return True, ""
# 找出差异
differences = ValidationEngine._find_differences(expected, actual)
return False, f"响应体不匹配: {differences}"
@staticmethod
def validate_contains(expected_value: Any, actual_value: Any) -> Tuple[bool, str]:
"""
验证包含关系
Args:
expected_value: 期望包含的值
actual_value: 实际值
Returns:
(是否通过, 错误消息)
"""
if isinstance(actual_value, (str, list, dict)):
if expected_value in actual_value:
return True, ""
return False, f"期望值'{expected_value}'不在实际值中"
if expected_value == actual_value:
return True, ""
return False, f"期望包含'{expected_value}',实际为'{actual_value}'"
@staticmethod
def validate_equals(expected_value: Any, actual_value: Any) -> Tuple[bool, str]:
"""
验证相等关系
Args:
expected_value: 期望的值
actual_value: 实际的值
Returns:
(是否通过, 错误消息)
"""
if expected_value == actual_value:
return True, ""
return False, f"期望值'{expected_value}',实际值'{actual_value}'"
@staticmethod
def validate_json_path(path: str, expected_value: Any, actual_data: Dict[str, Any]) -> Tuple[bool, str]:
"""
验证JSON路径
Args:
path: JSON路径(如"data.user.id"
expected_value: 期望的值
actual_data: 实际的数据
Returns:
(是否通过, 错误消息)
"""
try:
keys = path.split('.')
value = actual_data
for key in keys:
if isinstance(value, dict):
value = value.get(key)
elif isinstance(value, list) and key.isdigit():
value = value[int(key)]
else:
return False, f"路径'{path}'不存在"
if value == expected_value:
return True, ""
return False, f"路径'{path}'期望值'{expected_value}',实际值'{value}'"
except Exception as e:
return False, f"验证JSON路径失败: {str(e)}"
@staticmethod
def validate_regex(pattern: str, actual_value: str) -> Tuple[bool, str]:
"""
验证正则表达式
Args:
pattern: 正则表达式模式
actual_value: 实际的值
Returns:
(是否通过, 错误消息)
"""
try:
if re.match(pattern, str(actual_value)):
return True, ""
return False, f"'{actual_value}'不匹配正则表达式'{pattern}'"
except Exception as e:
return False, f"正则表达式验证失败: {str(e)}"
@staticmethod
def validate_header(expected_header: Dict[str, str], actual_headers: Dict[str, str]) -> Tuple[bool, str]:
"""
验证响应头
Args:
expected_header: 期望的响应头
actual_headers: 实际的响应头
Returns:
(是否通过, 错误消息)
"""
for key, expected_value in expected_header.items():
actual_value = actual_headers.get(key)
if actual_value is None:
return False, f"缺少响应头: {key}"
if actual_value != expected_value:
return False, f"响应头'{key}'期望值'{expected_value}',实际值'{actual_value}'"
return True, ""
@staticmethod
def validate_response_time(expected_max_time: float, actual_time: float) -> Tuple[bool, str]:
"""
验证响应时间
Args:
expected_max_time: 期望的最大响应时间(毫秒)
actual_time: 实际的响应时间(毫秒)
Returns:
(是否通过, 错误消息)
"""
if actual_time <= expected_max_time:
return True, ""
return False, f"响应时间{actual_time}ms超过期望最大值{expected_max_time}ms"
@staticmethod
def validate_schema(expected_schema: Dict[str, Any], actual_data: Dict[str, Any]) -> Tuple[bool, str]:
"""
验证数据结构
Args:
expected_schema: 期望的结构(简化版)
actual_data: 实际的数据
Returns:
(是否通过, 错误消息)
"""
for key, expected_type in expected_schema.items():
if key not in actual_data:
return False, f"缺少字段: {key}"
actual_value = actual_data[key]
if expected_type == "string" and not isinstance(actual_value, str):
return False, f"字段'{key}'期望类型string,实际类型{type(actual_value).__name__}"
elif expected_type == "number" and not isinstance(actual_value, (int, float)):
return False, f"字段'{key}'期望类型number,实际类型{type(actual_value).__name__}"
elif expected_type == "boolean" and not isinstance(actual_value, bool):
return False, f"字段'{key}'期望类型boolean,实际类型{type(actual_value).__name__}"
elif expected_type == "array" and not isinstance(actual_value, list):
return False, f"字段'{key}'期望类型array,实际类型{type(actual_value).__name__}"
elif expected_type == "object" and not isinstance(actual_value, dict):
return False, f"字段'{key}'期望类型object,实际类型{type(actual_value).__name__}"
return True, ""
@staticmethod
def _find_differences(expected: Any, actual: Any, path: str = "") -> str:
"""
找出两个值之间的差异
Args:
expected: 期望的值
actual: 实际的值
path: 当前路径
Returns:
差异描述
"""
if expected == actual:
return ""
if isinstance(expected, dict) and isinstance(actual, dict):
differences = []
all_keys = set(expected.keys()) | set(actual.keys())
for key in all_keys:
new_path = f"{path}.{key}" if path else key
if key not in expected:
differences.append(f"{new_path}: 实际存在但期望不存在")
elif key not in actual:
differences.append(f"{new_path}: 期望存在但实际不存在")
else:
diff = ValidationEngine._find_differences(expected[key], actual[key], new_path)
if diff:
differences.append(diff)
return "; ".join(differences)
elif isinstance(expected, list) and isinstance(actual, list):
if len(expected) != len(actual):
return f"{path}: 长度不匹配(期望{len(expected)},实际{len(actual)}"
differences = []
for i, (exp_item, act_item) in enumerate(zip(expected, actual)):
new_path = f"{path}[{i}]"
diff = ValidationEngine._find_differences(exp_item, act_item, new_path)
if diff:
differences.append(diff)
return "; ".join(differences)
else:
return f"{path}: 期望'{expected}',实际'{actual}'"
class ValidationRule:
"""验证规则"""
def __init__(self, rule_type: str, expected_value: Any = None, path: str = None):
"""
初始化验证规则
Args:
rule_type: 规则类型(status_code, contains, equals, json_path, regex, header, response_time, schema
expected_value: 期望值
path: JSON路径(仅用于json_path规则)
"""
self.rule_type = rule_type
self.expected_value = expected_value
self.path = path
def validate(self, actual_value: Any = None, actual_data: Dict[str, Any] = None) -> Tuple[bool, str]:
"""
执行验证
Args:
actual_value: 实际值
actual_data: 实际数据(用于JSON路径验证)
Returns:
(是否通过, 错误消息)
"""
if self.rule_type == "status_code":
return ValidationEngine.validate_status_code(self.expected_value, actual_value)
elif self.rule_type == "contains":
return ValidationEngine.validate_contains(self.expected_value, actual_value)
elif self.rule_type == "equals":
return ValidationEngine.validate_equals(self.expected_value, actual_value)
elif self.rule_type == "json_path":
return ValidationEngine.validate_json_path(self.path, self.expected_value, actual_data)
elif self.rule_type == "regex":
return ValidationEngine.validate_regex(self.expected_value, actual_value)
elif self.rule_type == "header":
return ValidationEngine.validate_header(self.expected_value, actual_value)
elif self.rule_type == "response_time":
return ValidationEngine.validate_response_time(self.expected_value, actual_value)
elif self.rule_type == "schema":
return ValidationEngine.validate_schema(self.expected_value, actual_data)
else:
return False, f"未知的验证规则类型: {self.rule_type}"