
对应代码core/validator.py、testcases/yaml/注册登录等接口测试.yaml说明本节所有代码示例均来自一个真实的移动端自动化测试项目业务名称和API路径已做模糊化处理。验证逻辑如果散落在每个测试函数里改一个验证规则就要改 N 个地方。Validator把验证抽象成规则引擎测试用例只传数据 规则Validator返回(passed, message)元组。配套代码见core/validator.py。Validator 接口总览Validator提供三个静态方法# API 响应验证 Validator.validate_api_response(response_data, expected) # UI 元素验证 Validator.validate_ui_element(driver, element_locator, expected) # 预期结果格式解析 Validator.parse_expected(expected)每个方法都返回tuple[bool, str]第一个元素表示是否通过第二个是详细错误信息。validate_api_response — API 响应验证staticmethod def validate_api_response(response_data: Any, expected: Dict[str, Any]) - tuple[bool, str]:参数说明response_data可以是 dict、JSON 字符串或原始响应对象。内部会尝试json.loads()解析字符串。expected字典支持三种验证方面status_code— 验证 HTTP 状态码contains— 验证响应体包含指定文本fields— 字段级精确/规则验证# core/validator.py 中的使用示例 from core.validator import Validator response { status_code: 200, response: { code: SUCCESS, message: 注册成功, data: { userId: u_12345, count: 1 } } } expected { status_code: 200, contains: 成功, fields: { code: SUCCESS, message: {contains: 成功}, data.userId: {exists: True}, data.count: {gte: 1} } } passed, msg Validator.validate_api_response(response, expected) assert passed, msg字段路径支持嵌套和数组索引_get_nested_field方法支持用点号分隔的路径以及数组索引语法items[0]# data.items[0].name → response[data][items][0][name]路径层级没有硬性限制但建议不超过 4 层否则调试报错时追踪路径很麻烦。比如data.items[0].order.detail还能接受再深就该考虑重构响应结构了。字段验证规则对照表规则示例说明精确匹配code: SUCCESSexpected 不是 dict 时走简单相等比较exists{exists: True}字段是否存在不关心值contains{contains: 成功}字符串包含匹配gt/gte{gte: 1}数值比较内部float()转换lt/lte{lt: 100}数值比较regex{regex: ^test.*}正则匹配使用re.matchtype{type: int}Python 类型名比较validate_ui_element — UI 元素验证staticmethod def validate_ui_element(driver, element_locator: Dict[str, str], expected: Dict[str, Any]) - tuple[bool, str]:element_locator格式为{type: id, value: com.example:id/btn_login}。底层调用BasePage.find_element。支持的验证方面exists— 布尔值控制元素是否存在text— 精确文本匹配text_contains— 文本包含匹配enabled— 是否可点击displayed— 是否可见attribute— 任意属性验证如{attribute: {content-desc: 登录}}from core.validator import Validator locator {type: accessibility_id, value: btn_login} expected { exists: True, text: 登录, displayed: True, enabled: True } passed, msg Validator.validate_ui_element(driver, locator, expected)parse_expected — 灵活格式适配如果从 YAML 或配置中读到的expected字段是纯字符串比如只用文本包含验证parse_expected会自动包装成字典格式Validator.parse_expected(成功) # → {contains: 成功} Validator.parse_expected(200) # → {equals: 200} Validator.parse_expected({status_code: 200}) # → 原样返回常见踩坑记录坑 1_validate_field中existsFalse的处理当expected中写{exists: False}时代码里的逻辑是if exists in expected: should_exist expected[exists] actually_exists actual_value is not None if should_exist ! actually_exists: return False, ... return True, 如果你期望字段不存在但响应里字段值为None_get_nested_field返回Noneactually_exists为False所以should_existFalse且actually_existsFalse验证通过。但如果你期望字段不存在而字段实际有值会报错字段 data.id 存在性不匹配: 期望 不存在, 实际 存在坑 2数值比较抛 ValueErrorif gt in expected: try: if float(actual_value) float(expected[gt]): return False, ... except (ValueError, TypeError): return False, f字段 {field_path} 无法比较大小, 实际值: {actual_value}字段值是字符串abc或者None时float()直接抛异常错误信息形如字段 data.count 无法比较大小, 实际值: None所以数值类型的字段要先确认值不是None或者用type规则先验证类型。坑 3_validate_field中 expected 是 dict 时的短路逻辑看这段代码if isinstance(expected, dict): if exists in expected: ... return True, # ← 早期 return if actual_value is None: return False, f字段 {field_path} 不存在如果 rules 里有exists且验证通过就直接return True不会继续验证 contains/gt/regex 等。换句话说{exists: True, regex: ^test}这种配置exists 通过后 regex 根本不执行。想同时验证存在性和内容只能用两条独立规则或者分两次调_validate_field。坑 4validate_api_response中contains是对整个响应体做字符串匹配if contains in expected: expected_text str(expected[contains]).lower() actual_text str(actual_data).lower() if expected_text not in actual_text: return False, f响应中不包含预期文本: {expected[contains]}注意actual_data可能是从response_data[response]提取的也可能是整个response_data。如果你传入了包含status_code和response的完整字典contains检查的是response子字段的内容。如果传的是裸 JSON则检查整个 dict 的字符串表示。这会导致一种隐蔽的问题大响应体被str()后可能误匹配到意料之外的子串。建议用fields里的contains做字段级匹配更精确。坑 5UI 元素验证超时不一致validate_ui_element内部对exists检查用了timeout3但后续获取元素用了timeout5。如果元素加载较慢超过 3 秒但不超过 5 秒exists检测会认为元素不存在元素存在性不匹配: 期望 存在, 实际 不存在而如果你跳过exists直接验证text反而不超时。所以在慢速页面上要么统一调大BasePage.find_element的默认超时要么先等元素稳定再传给 Validator。配合 YAML 用例的使用模式测试用例在 YAML 中定义expected字段框架调用Validator.parse_expected解析后传入validate_api_response# 注册接口测试用例 - name: register-step1 api: /api/auth/register/step1 method: POST body: email: testexample.com recommendTag: FRIEND_REF expected: status_code: 200 fields: code: SUCCESS message: contains: 成功 data.email: exists: true regex: ^[a-zA-Z0-9._%-][a-zA-Z0-9.-]\\.[a-zA-Z]{2,}$ data.userId: type: str data.count: gte: 1YAML 中的expected直接对应Validator.validate_api_response的第二个参数。改验证规则改 YAML 即可Validator不需要改动。