feat,fix(core,docs): 完善核心模块代码注释并添加架构改进文档
- 为 core 目录下主要模块 (models, context, creator, base_api, exchange, executor) 添加了详细的类和方法 Docstring。 - 新增 docs/架构改进.md 文件。
This commit is contained in:
@@ -6,7 +6,17 @@ from core.session import Session
|
||||
from core import settings
|
||||
|
||||
class BaseApi:
|
||||
"""
|
||||
所有 API 类的基类。
|
||||
提供基础的 Session 管理和日志记录功能,供具体的业务 API 类继承。
|
||||
"""
|
||||
def __init__(self, session: Session = None):
|
||||
"""
|
||||
初始化 BaseApi。
|
||||
|
||||
Args:
|
||||
session: HTTP 会话对象。如果未提供,将使用默认配置创建一个新的 Session。
|
||||
"""
|
||||
self.session = session or Session(base_url=settings.base_url)
|
||||
self.logger = logging.getLogger(self.__class__.__name__)
|
||||
|
||||
|
||||
@@ -22,6 +22,12 @@ class VariableStore:
|
||||
"""内存变量仓库:负责 L2 缓存与磁盘的唯一交互"""
|
||||
|
||||
def __init__(self, seed_file: Path):
|
||||
"""
|
||||
初始化变量仓库。
|
||||
|
||||
Args:
|
||||
seed_file: 初始变量文件路径(YAML格式),用于加载种子数据。
|
||||
"""
|
||||
self.seed_file = seed_file
|
||||
self.processor = YamlProcessor(seed_file)
|
||||
# 启动时仅加载一次
|
||||
|
||||
@@ -133,6 +133,15 @@ class CaseGenerator:
|
||||
|
||||
@classmethod
|
||||
def build_and_register(cls, target_cls: Type[TestTemplateBase], cases_dir: Union[str, Path]):
|
||||
"""
|
||||
构建测试用例并注册到目标测试类中。
|
||||
|
||||
遍历指定目录下的用例文件,解析数据,生成测试方法并动态绑定到 target_cls 上。
|
||||
|
||||
Args:
|
||||
target_cls: 目标测试类(通常继承自 TestTemplateBase)。
|
||||
cases_dir: 测试用例文件所在的目录路径。
|
||||
"""
|
||||
# 1. 通过 Loader 获取数据
|
||||
all_cases = CaseDataLoader.get_all_cases(cases_dir)
|
||||
for index, case_info in enumerate(all_cases):
|
||||
@@ -149,7 +158,18 @@ class CaseGenerator:
|
||||
|
||||
@staticmethod
|
||||
def _create_case_method(title, entity: CaseEntity):
|
||||
"""封装具体的 pytest 执行节点"""
|
||||
"""
|
||||
封装具体的 pytest 执行节点。
|
||||
|
||||
创建并返回一个闭包函数,该函数包含完整的测试执行逻辑(Allure 设置、日志、执行器调用)。
|
||||
|
||||
Args:
|
||||
title: 测试用例标题。
|
||||
entity: 包含用例数据和上下文的实体对象。
|
||||
|
||||
Returns:
|
||||
function: 可被 pytest 识别和执行的测试方法。
|
||||
"""
|
||||
case_template = entity.step_data
|
||||
context = entity.row_context
|
||||
def build_actual_case(instance: TestTemplateBase, execution_context):
|
||||
|
||||
@@ -24,17 +24,31 @@ T = TypeVar("T", bound=Union[dict, list, str, Any])
|
||||
|
||||
|
||||
class Exchange:
|
||||
"""
|
||||
变量交换器类。
|
||||
负责管理全局变量缓存,核心职能包括:
|
||||
1. Extract: 从响应结果中提取变量。
|
||||
2. Replace: 将数据中的变量占位符替换为实际值。
|
||||
"""
|
||||
def __init__(self, variable_cache: dict[str, Any]):
|
||||
"""
|
||||
初始化交换器。
|
||||
|
||||
Args:
|
||||
variable_cache: 初始变量缓存字典(引用传递,修改会影响源数据)。
|
||||
"""
|
||||
self._cache = variable_cache
|
||||
# 匹配标准变量 ${var},排除函数调用 ${func()}
|
||||
self.var_only_pattern = re.compile(r"^\$\{([a-zA-Z_]\w*)}$")
|
||||
|
||||
@property
|
||||
def global_vars(self) -> dict:
|
||||
"""获取当前全局变量缓存。"""
|
||||
return self._cache
|
||||
|
||||
@global_vars.setter
|
||||
def global_vars(self, global_vars: dict) -> None:
|
||||
"""设置全局变量缓存(通常用于上下文切换,如 ChainMap 合并)。"""
|
||||
self._cache = global_vars
|
||||
|
||||
def extract(self, resp: Any, var_name: str, attr: str, expr: str, index: int = 0):
|
||||
|
||||
@@ -25,6 +25,13 @@ VALIDATE_LIST_ADAPTER = TypeAdapter(List[ValidateItem])
|
||||
|
||||
|
||||
class WorkflowExecutor:
|
||||
"""
|
||||
工作流执行器。
|
||||
作为测试执行的核心引擎,负责调度单个用例的完整生命周期:
|
||||
1. 上下文准备(变量池合并)。
|
||||
2. 动作路由与执行(HTTP 请求或 PO 方法反射调用)。
|
||||
3. 后处理(变量提取与断言校验)。
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def perform(cls, case_info: RawSchema, env: ExecutionEnv, context: Optional[dict[str, Any]] = None) -> Any:
|
||||
@@ -74,7 +81,7 @@ class WorkflowExecutor:
|
||||
@staticmethod
|
||||
def _execute_po_method(action: ApiActionModel, env: ExecutionEnv):
|
||||
"""核心反射逻辑:根据字符串动态加载 api/ 目录下的类并执行方法"""
|
||||
class_name = action.api_class
|
||||
class_name = action.module
|
||||
method_name = action.method
|
||||
params = action.params or {}
|
||||
# 1. 确定模块路径:优先级策略
|
||||
|
||||
@@ -18,6 +18,10 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class HttpAction(BaseModel):
|
||||
"""
|
||||
HTTP 请求动作模型。
|
||||
定义了发起 HTTP 请求所需的所有参数,包括方法、URL、头信息、参数、请求体等。
|
||||
"""
|
||||
method: str = Field(..., description="HTTP 请求方法: get, post, etc.")
|
||||
url: str = Field(..., description="接口路径或完整 URL")
|
||||
headers: dict[str, Any] | None = Field(default=None, description="HTTP 请求头")
|
||||
@@ -31,6 +35,10 @@ class HttpAction(BaseModel):
|
||||
|
||||
|
||||
class ApiActionModel(BaseModel):
|
||||
"""
|
||||
PO (Page Object) 模式动作模型。
|
||||
定义了调用封装在 API 类中的方法所需的信息,通过反射机制动态执行。
|
||||
"""
|
||||
module: str = Field(..., alias="class", description="要调用的 API 类名")
|
||||
method: str = Field(..., description="类中的方法名")
|
||||
params: dict[str, Any] = Field(default_factory=dict, description="传给方法的参数")
|
||||
@@ -39,6 +47,10 @@ class ApiActionModel(BaseModel):
|
||||
|
||||
|
||||
class ValidateItem(BaseModel):
|
||||
"""
|
||||
断言项模型。
|
||||
定义了测试用例执行后的校验规则,包括检查字段、断言方法和期望值。
|
||||
"""
|
||||
check: str = Field(..., description="要检查的字段或表达式")
|
||||
assert_method: str = Field(alias="assert", default="equals")
|
||||
expect: Any = Field(..., description="期望值")
|
||||
@@ -48,6 +60,10 @@ class ValidateItem(BaseModel):
|
||||
|
||||
|
||||
class RawSchema(BaseModel):
|
||||
"""
|
||||
测试用例原始数据模型。
|
||||
对应 YAML 用例文件的结构,包含元数据、动作定义、变量提取和断言规则。
|
||||
"""
|
||||
title: str = Field(..., description="用例标题")
|
||||
epic: str | None = None
|
||||
feature: str | None = None
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
@Software: PyCharm
|
||||
@contact: t6i888@163.com
|
||||
@file: session.py
|
||||
@date: 2024 2024/9/12 21:56
|
||||
@date: 2024/9/12 21:56
|
||||
@desc:
|
||||
"""
|
||||
import logging
|
||||
@@ -19,22 +19,69 @@ import allure
|
||||
|
||||
# logger = logging.getLogger("requests.session")
|
||||
logger = logging.getLogger(__name__)
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
# logging.basicConfig(level=logging.INFO)
|
||||
|
||||
|
||||
class Session(requests.Session):
|
||||
"""
|
||||
自定义会话管理类,继承自 requests.Session。
|
||||
|
||||
增强功能:
|
||||
1. Base URL 管理:支持相对路径自动拼接。
|
||||
2. Allure 集成:自动将请求操作包装为 Allure 步骤。
|
||||
3. 日志记录:详细记录请求和响应的 头部、正文、状态码等信息。
|
||||
"""
|
||||
|
||||
def __init__(self, base_url=None):
|
||||
"""
|
||||
初始化会话。
|
||||
|
||||
Args:
|
||||
base_url: 基础 URL,用于拼接相对路径请求。
|
||||
"""
|
||||
super().__init__() # 先执行父类的初始化
|
||||
self.base_url = base_url # 在执行子类的初始化操作
|
||||
|
||||
@allure.step("发送请求")
|
||||
def request(self, method, url: str, *args, **kwargs) -> Response:
|
||||
"""
|
||||
发送 HTTP 请求(重写)。
|
||||
|
||||
逻辑:
|
||||
1. 如果 url 是相对路径,自动拼接 base_url。
|
||||
2. 记录 Allure 步骤。
|
||||
|
||||
Args:
|
||||
method: 请求方法 (GET, POST, etc.)
|
||||
url: 请求 URL (支持相对路径)
|
||||
*args: 透传给 requests.Session.request 的位置参数
|
||||
**kwargs: 透传给 requests.Session.request 的关键字参数
|
||||
|
||||
Returns:
|
||||
Response: 响应对象
|
||||
"""
|
||||
if not url.startswith("http"):
|
||||
# 自动添加baseurl
|
||||
url = urljoin(self.base_url, url)
|
||||
return super().request(method, url, *args, **kwargs) # 按照原有方式执行
|
||||
|
||||
def send(self, request: PreparedRequest, *args, **kwargs) -> Response:
|
||||
"""
|
||||
发送底层 PreparedRequest(重写)。
|
||||
|
||||
逻辑:
|
||||
1. 记录请求详细日志 (URL, Headers, Body)。
|
||||
2. 执行真实网络请求。
|
||||
3. 记录响应详细日志 (Status, Headers, Body)。
|
||||
|
||||
Args:
|
||||
request: 已准备好的请求对象
|
||||
*args: 透传参数
|
||||
**kwargs: 透传参数
|
||||
|
||||
Returns:
|
||||
Response: 响应对象
|
||||
"""
|
||||
logger.info(f"发送请求>>>>>> 接口地址 = {request.method} {request.url}")
|
||||
logger.info(f"发送请求>>>>>> 请求头 = {request.headers}")
|
||||
logger.info(f"发送请求>>>>>> 请求正文 = {request.body} ")
|
||||
|
||||
Reference in New Issue
Block a user