- 引入 SmartInt 和 SmartDict 类型,支持 YAML 占位符与业务类型的自动转换。 - 优化 CaseInfo 互斥校验逻辑,确保 request 与 api_action 二选一。 - 统一使用 Pydantic V2 的 model_config 规范。 - 将变量替换时机提前至模型实例化之前,支持占位符在校验前完成真实值注入, 保证了 int/bool 等字段的类型转换正确性。 - 优化断言渲染时机,支持响应提取值关联。
108 lines
3.1 KiB
Python
108 lines
3.1 KiB
Python
#!/usr/bin/env python
|
|
# coding=utf-8
|
|
|
|
"""
|
|
@author: CNWei
|
|
@Software: PyCharm
|
|
@contact: t6i888@163.com
|
|
@file: case_validator
|
|
@date: 2025/2/27 17:25
|
|
@desc:
|
|
"""
|
|
import logging
|
|
from typing import List, Union, Any
|
|
|
|
from pydantic import TypeAdapter
|
|
|
|
from core.exchange import Exchange
|
|
from core.models import ValidateItem
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
VALIDATE_LIST_ADAPTER = TypeAdapter(List[ValidateItem])
|
|
|
|
class CaseValidator:
|
|
VALIDATORS = {}
|
|
|
|
@classmethod
|
|
def register(cls, name: str):
|
|
def decorator(func):
|
|
cls.VALIDATORS[name] = func
|
|
return func
|
|
|
|
return decorator
|
|
|
|
@classmethod
|
|
def validate(cls,response: Any, validate_list: List[ValidateItem]):
|
|
"""
|
|
核心断言入口:适配 CaseInfo.validate_data (List[ValidateItem])
|
|
"""
|
|
if not validate_list:
|
|
return
|
|
# dicts = [
|
|
# item.model_dump(by_alias=True) if isinstance(item, ValidateItem) else item for item in validate_list
|
|
# ]
|
|
# rendered = exchanger.replace(dicts)
|
|
# # 触发 SmartInt/SmartDict 类型修复
|
|
# final_list = VALIDATE_LIST_ADAPTER.validate_python(rendered)
|
|
|
|
for item in validate_list:
|
|
# 1. 提取模型中的数据
|
|
# 此时 final_case 里的 item 已经是经过变量替换后的实体
|
|
actual = item.check
|
|
expect = item.expect
|
|
method = item.assert_method # 即模型中的 alias="assert"
|
|
msg = item.msg or f"Assert {actual} {method} {expect}"
|
|
|
|
# 2. 获取对应的断言函数
|
|
validator = cls.VALIDATORS.get(method)
|
|
if not validator:
|
|
logger.error(f"❌ 不支持的断言方式: {method}")
|
|
raise KeyError(f"Unsupported validator: {method}")
|
|
|
|
# 3. 执行断言
|
|
try:
|
|
validator(actual, expect, msg)
|
|
except AssertionError as e:
|
|
logger.error(
|
|
f"❌ 断言失败: {msg} | 实际值: {actual} ({type(actual)}), 期望值: {expect} ({type(expect)})")
|
|
raise e
|
|
|
|
|
|
@CaseValidator.register('equals')
|
|
def validate_equals(a, b, msg):
|
|
logger.info(f"assert {a} == {b}, {msg} 执行这段代码")
|
|
print(f"assert {a} == {b}, {msg} 执行这段代码")
|
|
assert a == b, msg
|
|
|
|
|
|
@CaseValidator.register('not_equals')
|
|
def validate_not_equals(a, b, msg):
|
|
logger.info(f"assert {a} != {b}, {msg}")
|
|
assert a != b, msg
|
|
|
|
|
|
@CaseValidator.register('contains')
|
|
def validate_contains(a, b, msg):
|
|
logger.info(f"assert {a} in {b}, {msg}")
|
|
assert a in b, msg
|
|
|
|
|
|
@CaseValidator.register('not_contains')
|
|
def validate_not_contains(a, b, msg):
|
|
logger.info(f"assert {a} not in {b}, {msg}")
|
|
assert a not in b, msg
|
|
|
|
|
|
if __name__ == '__main__':
|
|
resp=None
|
|
mock_case = [
|
|
{"check": 100, "expect": 100, "assert": "equals"},
|
|
{"check": "success", "expect": "success", "assert": "contains"}
|
|
]
|
|
final_validate_list = VALIDATE_LIST_ADAPTER.validate_python(mock_case)
|
|
case_validator = CaseValidator()
|
|
print(case_validator.VALIDATORS)
|
|
case_validator.validate(resp,final_validate_list)
|