- 为 core 目录下主要模块 (models, context, creator, base_api, exchange, executor) 添加了详细的类和方法 Docstring。 - 新增 docs/架构改进.md 文件。
145 lines
5.1 KiB
Python
145 lines
5.1 KiB
Python
#!/usr/bin/env python
|
||
# coding=utf-8
|
||
|
||
"""
|
||
@author: chen wei
|
||
@Software: PyCharm
|
||
@contact: t6i888@163.com
|
||
@file: models.py
|
||
@date: 2024 2024/9/15 21:14
|
||
@desc: 声明yaml用例格式
|
||
"""
|
||
import logging
|
||
from typing import List, Any
|
||
|
||
from pydantic import BaseModel, Field, ConfigDict
|
||
|
||
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 请求头")
|
||
params: dict[str, Any] | None = Field(default=None, description="URL 查询参数")
|
||
data: dict[str, Any] | None = None
|
||
json_body: Any | None = Field(default=None, alias="json")
|
||
timeout: int = 10
|
||
files: dict[str, Any] | None = None
|
||
|
||
model_config = ConfigDict(extra="allow", populate_by_name=True)
|
||
|
||
|
||
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="传给方法的参数")
|
||
|
||
model_config = ConfigDict(populate_by_name=True)
|
||
|
||
|
||
class ValidateItem(BaseModel):
|
||
"""
|
||
断言项模型。
|
||
定义了测试用例执行后的校验规则,包括检查字段、断言方法和期望值。
|
||
"""
|
||
check: str = Field(..., description="要检查的字段或表达式")
|
||
assert_method: str = Field(alias="assert", default="equals")
|
||
expect: Any = Field(..., description="期望值")
|
||
msg: str = Field(default="Assertion", description="断言描述")
|
||
|
||
model_config = ConfigDict(populate_by_name=True)
|
||
|
||
|
||
class RawSchema(BaseModel):
|
||
"""
|
||
测试用例原始数据模型。
|
||
对应 YAML 用例文件的结构,包含元数据、动作定义、变量提取和断言规则。
|
||
"""
|
||
title: str = Field(..., description="用例标题")
|
||
epic: str | None = None
|
||
feature: str | None = None
|
||
story: str | None = None
|
||
# 统一使用 action 字段承载业务逻辑 (Http 或 PO)
|
||
action: dict[str, Any] = Field(description="请求内容或PO动作内容")
|
||
extract: dict[str, List[Any]] | None = Field(
|
||
default=None,
|
||
description="变量提取表达式,格式: {变量名: [来源, 表达式, 索引]}"
|
||
)
|
||
validate_data: List[Any] = Field(
|
||
default_factory=list,
|
||
alias="validate",
|
||
description="断言信息"
|
||
)
|
||
|
||
model_config = ConfigDict(extra="allow",
|
||
populate_by_name=True, # 无论是在代码中用 api_class 还是在 YAML 中用 class 赋值,Pydantic 都能正确识别。
|
||
arbitrary_types_allowed=True # 允许在模型中使用非 Pydantic 标准类型(如自定义类实例)
|
||
) # 允许参数化等额外字段
|
||
|
||
def is_po_mode(self) -> bool:
|
||
"""判断是否为 PO 模式"""
|
||
return "class" in self.action or "module" in self.action
|
||
|
||
|
||
if __name__ == '__main__':
|
||
# 模拟数据 1:标准请求模式
|
||
raw_case_1 = {
|
||
"title": "查询状态信息",
|
||
"action": {
|
||
"method": "get",
|
||
"url": "/api/v1/info",
|
||
"headers": {"User-Agent": "pytest-ai"},
|
||
"json": {"User-Agent": "pytest-ai"}
|
||
},
|
||
"validate": [
|
||
{"check": "status_code", "assert": "equals", "expect": 200, "msg": "响应码200"},
|
||
{"check": "$.msg", "expect": "Success"}
|
||
]
|
||
}
|
||
|
||
# 模拟数据 2:PO 模式 (反射调用)
|
||
raw_case_2 = {
|
||
"title": "用户登录测试",
|
||
"action": {
|
||
"class": "UserAPI",
|
||
"method": "login",
|
||
"params": {"user": "admin", "pwd": "123"}
|
||
},
|
||
"extract": {
|
||
"token": ["json", "$.data.token", 0]
|
||
}
|
||
}
|
||
|
||
print("--- 开始模型校验测试 ---\n")
|
||
|
||
try:
|
||
# 验证模式 1
|
||
case1 = RawSchema(**raw_case_1)
|
||
print(f"✅ 模式1 (Request) 校验通过: {case1.title}")
|
||
print(f" http: {case1.action}")
|
||
print(f" 断言规则数: {len(case1.validate_data)}\n")
|
||
|
||
# 验证模式 2
|
||
case2 = RawSchema(**raw_case_2)
|
||
print(f"✅ 模式2 (PO Mode) 校验通过: {case2.title}")
|
||
print(f" api: {case2.action}")
|
||
print(f" 提取规则数: {len(case2.extract)}\n")
|
||
|
||
# 验证非法数据(如:既没有 request 也没有 api_action 的情况可以在业务层进一步校验)
|
||
# 这里演示 Pydantic 自动类型转换
|
||
invalid_data = {"title": "错误用例", "action": {"url": "/api"}} # 缺少 method
|
||
print("--- 预期失败测试 ---")
|
||
RawSchema(**invalid_data)
|
||
|
||
except Exception as e:
|
||
print(f"❌ 预期内的校验失败: \n{e}")
|