当前位置: 首页 > news >正文

【日常学习8】2025-9-3 学习控件Day2

输入控件分为:输入控件基类,输入控件类,具体输入定位器,

像xxxLoc这个控件就是具体输入控件inputctrl,是定位器通过xpath得来的具体框元素。

而OnlyInput这个控件就是输入控件类,不需要传入具体inputctrl定位,由父类获取具体文本框/文本域,别的类型交给radio checkbox控件类。

radio里面有具体的定位器,类方法里根据不同的情况选择不同的定位器,比如:

if isinstance(value, str):radio_ctrl_obj = self.find_child(self.radio_ctrlLoc.format_key(value))radio_ctrl_obj.click()return radio_ctrl_obj

1.MessageItemCtrl(输入控件)

是一个处理 “消息项启停用状态” 的控件,主要用于管理系统中各类消息项(如通知、提醒等)的启用或停用状态,支持批量操作和状态校验。

系统设置,消息设置页面专属控件。

一、基础信息:定位规则与继承

# 导入输入控件基类:提供元素查找、基础操作等通用能力
from frameworkCore.business.InputCtrlBase import InputCtrlBase;
# 导入定位工具:定义如何找到消息项的状态按钮
from frameworkCore.driver.locator import Locator
from frameworkCore.driver.by import By
# 导入重试装饰器:处理操作可能出现的临时问题(如点击后状态未立即更新)
from frameworkCore.common.decorator import retry
# 导入运行上下文:(当前代码未直接使用,预留扩展)
from frameworkCore.business.runContext import RunContextclass MessageItemCtrl(InputCtrlBase):# 定位“消息项的启停用状态按钮”# 规则:在class为"message-item"的消息项中,找到标题为{key}的消息,再定位其状态切换按钮statusLoc = Locator(By.XPATH,'.//div[@class="message-item"]//div[ @title="{}"]/parent::div/parent::div/div[@class="message-content-switch"]',wait=2,desc="启停用状态按钮")

  • statusLoc定位器:通过消息项的title属性({}占位符)精准定位对应消息项的状态切换按钮(比如 “订单通知”“库存预警” 等不同消息项的开关)。

二、核心方法input():批量设置消息项状态

@retry()  # 操作失败时自动重试(如状态切换后未立即生效)
def input(self, value):# value是字典格式:{消息项名称: 目标状态},如{"订单通知": True, "库存预警": False}# True表示“启用”,False表示“停用”# 遍历字典中的每个消息项for key in value:# 1. 定位到当前消息项的状态按钮(用key替换占位符,如"订单通知")itemEle = self.find_child(self.statusLoc.format_key(key))# 2. 获取当前状态status = self.__getItemStatus(itemEle)# 3. 判断是否需要操作:如果当前状态与目标状态一致,跳过;否则点击切换if value[key] == status:continue  # 状态一致,无需操作else:itemEle.mouse_click()  # 点击状态按钮切换状态# 4. 再次获取状态并校验是否切换成功status = self.__getItemStatus(itemEle)assert status == value[key]  # 校验失败则抛出错误

逻辑拆解
这个方法支持批量处理多个消息项的状态,流程是 “定位→查状态→按需操作→校验”,确保每个消息项都能准确切换到目标状态。

三、辅助方法:获取状态

def __getItemStatus(self, ele):# 私有方法:根据状态按钮的文本判断当前状态status = ele.text()  # 获取按钮上的文本(如"已启用"或"已停用")# 转换为布尔值:"已启用"→True,其他→FalsebStatus = True if status == '已启用' else Falsereturn bStatusdef getItemStatus(self, name):# 公开方法:获取指定消息项的当前状态# 1. 定位到目标消息项的状态按钮itemEle = self.find_child(self.statusLoc.format_key(name))# 2. 调用私有方法返回状态return self.__getItemStatus(itemEle)

在input方法里使用的是私有方法,每一步使用私有方法前都find_child了,但是外部要想调用公开方法,返回值是私有方法返回的,那么就应该在公开方法内部先加上find_child定位到目标消息项的当前状态。

  • __getItemStatus(私有方法):将前端显示的文本(“已启用”/“已停用”)转换为程序易处理的布尔值(True/False),方便逻辑判断。
  • getItemStatus(公开方法):允许外部查询某个消息项的当前状态(比如测试用例需要先检查状态再执行操作)。

四、text()方法:复用父类功能

def text(self):return super().text()  # 调用父类的text()方法,获取控件文本(当前场景中用途较少)

2.OnlyInputComp

是一个专注于 “纯输入操作” 的组件,继承自InputComp,专门处理各种表单输入场景(包括普通文本输入、单选框、复选框等),核心特点是 “简化输入逻辑,只关注输入操作本身”。

一、基础信息:继承与依赖

# 注释了注册装饰器,说明可能是内部使用或测试中的组件
# @register_comp
class OnlyInputComp(InputComp):  # 继承自InputComp,复用基础输入逻辑# 直接输入的控件对象(不需要预先定义定位器,灵活接收外部传入的元素)inputCtrl = None  # 不用定位,只用输入逻辑

  • 继承InputComp:获得父类的基础输入能力,但弱化了 “定位元素” 的逻辑(inputCtrl可以直接由外部传入)。
  • 灵活性高:不强制依赖预定义的定位器,而是通过inputCtrl动态接收需要操作的输入元素,适配各种输入场景。

二、初始化方法__init__:接收输入元素

def __init__(self, ctrl=None):self.inputCtrl = ctrl  # 接收外部传入的输入元素(如文本框、单选框等),直接赋值给inputCtrl

作用
允许在创建OnlyInputComp实例时,直接传入一个已经定位好的输入元素(ctrl),跳过 “通过定位器查找元素” 的步骤,简化流程。例如:

# 先定位到一个文本框元素
text_input_ele = driver.find_element(By.ID, "username")
# 直接将元素传入OnlyInputComp
input_comp = OnlyInputComp(ctrl=text_input_ele)
# 调用输入方法
input_comp._input("admin")

三、核心方法_input:处理各种类型的输入

def _input(self, data):"""表单数据输入--直接输入and参照输入"""try:# 步骤1:如果inputCtrl未传入(外部没给元素),则自动查找输入框if self.inputCtrl is None:try:# 先尝试用父类的inputCtrlLoc定位普通输入框self.inputCtrl = self.find_child(self.inputCtrlLoc)except:# 如果失败,尝试定位文本域(textarea)self.inputCtrl = self.find_child(self.textareaInputCtrlLoc)# 步骤2:获取输入元素的类型(type属性),判断是哪种输入控件type = self.inputCtrl.getAttribute('type')# 步骤3:根据类型处理不同输入场景if type == 'radio':  # 单选框(radio)# 复用RadioCtrl控件处理单选逻辑radio_ctrl = RadioCtrl.instance(self.get_parent())radio_ctrl.input(data)  # 传入选项值(如"男"、"女")return False  # 处理完成,返回if type == 'checkbox':  # 复选框(checkbox)# 复用CheckBoxCtrl控件处理复选逻辑check_box_ctrl = CheckBoxCtrl().instance(self)check_box_ctrl.input(data)  # 传入选项列表(如["选项1", "选项2"])return False  # 处理完成,返回else:  # 其他类型(文本框、密码框等普通输入)self.inputCtrl.clear()  # 清空输入框self.inputCtrl.selectAll()  # 全选(确保清空彻底)self.inputCtrl.sendKeys(data)  # 输入数据(如文本、数字)time.sleep(0.1)  # 短暂等待,确保输入生效except Exception as err:# 捕获异常并包装,方便调试raise Exception("OnlyInputComp异常" + repr(err))

逻辑拆解
这个方法是输入操作的 “总控”,根据输入元素的类型(type)自动适配不同的输入逻辑,兼容多种表单控件:

  1. 元素获取逻辑

    • 优先使用外部传入的inputCtrl(如果有);
    • 若未传入,则自动查找普通输入框或文本域(复用父类的定位器)。
  2. 分类型处理

    • 单选框(radio):交给RadioCtrl控件处理(比如选择 “男” 或 “女”);
    • 复选框(checkbox):交给CheckBoxCtrl控件处理(比如勾选 “选项 A” 和 “选项 B”);
    • 普通输入(文本框等):直接执行 “清空→全选→输入” 流程(比如输入用户名、邮箱)。

四、_after_handler方法:输入后处理(预留)

def _after_handler(self, data):pass  # 空实现,用于输入后需要额外处理的场景(如触发校验、关闭弹窗等)

作用
这是一个 “钩子方法”,预留用于输入完成后的后续操作。例如:

  • 输入后需要点击 “确认” 按钮;
  • 输入后需要等待校验提示消失;
  • 未来可以根据业务需求重写这个方法,扩展功能。

五、这个控件的设计目的和适用场景

OnlyInputComp的核心设计目的是 **“简化输入操作,专注于输入本身”**,适用于以下场景:

  1. 快速输入:已经通过其他方式定位到输入元素,只想快速执行输入操作(无需重复定位);
  2. 多类型兼容:同一表单中既有文本框、又有单选 / 复选框,用一个控件统一处理;
  3. 轻量复用:不需要复杂的前置 / 后置逻辑,只需要基础的输入功能。

这段代码的核心是理解OnlyInputComp如何继承并复用父类InputCompBase的定位器,以及在inputCtrl未传入时如何自动查找输入框元素

InputCompBase中定义了一个通用的输入框定位器:

class InputCompBase(InputCtrlBase):# 定位规则:匹配所有非隐藏的input,或textarea(文本域)inputCtrlLoc = Locator(By.XPATH, ".//input[not(@type) or @type != 'hidden']|.//textarea",  # 关键定位规则wait=1)inputCtrl = None  # 用于保存找到的输入框元素

这个inputCtrlLoc是父类的 “通用输入框定位器”,作用是:
自动匹配两种常见输入元素:

  1. 所有非隐藏的input标签(@type != 'hidden')—— 包括文本框、密码框等;
  2. 所有textarea标签(多行文本域)。

OnlyInputComp_input方法中,当外部没有传入inputCtrl(即没有手动指定输入元素)时,会执行以下步骤:

if self.inputCtrl is None:  # 外部没传入输入元素try:# 步骤1:尝试用父类的inputCtrlLoc定位普通输入框self.inputCtrl = self.find_child(self.inputCtrlLoc)except:# 步骤2:如果失败,尝试定位文本域(textarea)self.inputCtrl = self.find_child(self.textareaInputCtrlLoc)
拆解逻辑:
  1. 为什么先尝试self.inputCtrlLoc
    self.inputCtrlLoc继承自父类InputCompBase,其定位规则是.//input[not(@type) or @type != 'hidden']|.//textarea,已经包含了textarea
    优先用这个定位器,是为了复用父类的通用规则,覆盖大多数输入场景(普通输入框 + 文本域)。

  2. 为什么需要except里的textareaInputCtrlLoc
    这是一种 “兼容处理”:

    • 某些特殊页面中,文本域(textarea)的结构可能比较特殊,父类的inputCtrlLoc可能定位不到(比如被特殊 class 包裹);
    • 因此OnlyInputComp可能在自己的类中单独定义了textareaInputCtrlLoc(专门针对文本域的更精确的定位器,比如Locator(By.XPATH, './/textarea[@class="special-textarea"]'));
    • 当父类的通用定位器失败时,就用子类专门定义的文本域定位器再试一次,提高定位成功率。

3.InputCompBase

是一个输入组件的基础类,为所有输入相关的控件(如文本框、单选框、文本域等)提供通用的输入逻辑、值校验和元素定位能力。它是框架中 “输入控件家族” 的父类,子类(如InputCompOnlyInputComp)可以继承并扩展它的功能。

文本框和文本域:

<input type="text" value="默认文本">
<textarea>默认多行文本</textarea>

一、核心定位与属性

class InputCompBase(InputCtrlBase):# 通用输入框定位器:匹配所有可见输入元素inputCtrlLoc = Locator(By.XPATH, ".//input[not(@type) or @type != 'hidden']|.//textarea",  # 核心定位规则wait=1)inputCtrl = None  # 用于存储找到的输入元素(如input、textarea等)

关键设计

  • inputCtrlLoc:一个 “万能定位器”,能匹配两种常见输入元素:
    1. 所有非隐藏的input标签(@type != 'hidden')—— 包括文本框、密码框、单选框等;
    2. 所有textarea标签(多行文本域)。
      这使得子类无需重复定义基础定位规则,直接复用即可。
  • inputCtrl:保存实际操作的输入元素(可以是外部传入,也可以通过inputCtrlLoc自动查找),是后续输入、校验的核心对象。

二、核心方法:input()—— 输入流程的总控

@retry()  # 操作失败时自动重试(解决网络延迟、元素未就绪等问题)
def input(self, data):# 调用子类实现的_input方法(具体输入逻辑由子类决定)result = self._input(data)# 如果输入成功(result为None或True),执行后续校验和处理if result is None or result is True:# 特殊情况:如果输入空字符串,直接返回(无需校验)if isinstance(data, str) and data == "":return# 校验输入值是否正确(核心步骤)self._assert_input_value(data)# 业务特殊处理:某些字段输入后不执行_after_handler(避免触发不必要的交互)# 例如:出库数量输入后回车可能导致弹窗关闭,收入汇率输入后会自动四舍五入if hasattr(self, 'key') and (self.key in ['出库数量', '出库数量2', '收入_汇率']):return# 输入后的附加处理(由子类实现,如触发回车、关闭弹窗等)self._after_handler(data)

子类_input的返回值是True或者False,结合刚刚子类OnlyInputCtrl的代码,如果是直接输入,就是文本类输入,需要校验文本值。但要是单选框复选框就交给别的输入控件,返回false,无需校验。

OnlyInputComp_input方法中,普通输入框的处理逻辑确实没有显式返回True

# OnlyInputComp的_input方法
else:  # 处理普通输入框(非radio/checkbox)self.inputCtrl.clear()self.inputCtrl.selectAll()self.inputCtrl.sendKeys(data)time.sleep(0.1)# 没有return语句

这是因为:
在 Python 中,函数如果没有显式 return,默认返回None

而父类input方法的判断条件是if result is None or result is TrueNone会被视为 “输入成功”,因此会继续执行后续的校验(_assert_input_value)和_after_handler

流程拆解
这个方法定义了 “输入操作” 的标准流程 ——执行输入→校验结果→附加处理,但把具体的输入逻辑(_input)和附加处理(_after_handler)交给子类实现,体现了 “模板方法模式” 的设计思想:

通用的写在父类,灵活的交给子类。

  1. 通用性:所有输入控件都需要 “校验结果”,因此_assert_input_value在父类中实现;
  2. 灵活性:不同控件的输入方式不同(如文本框直接输入、单选框点击选项),因此_input由子类定制。

三、校验方法:_assert_input_value—— 确保输入正确

@retry(1, 2)  # 重试1次,间隔2秒(解决输入后值未立即更新的问题)
def _assert_input_value(self, data):data = str(data)  # 统一转为字符串处理if data != '':  # 非空值校验# 如果是单值,转为列表便于统一遍历(支持多值校验扩展)if isinstance(data, str):data = [data]for value in data:# 移除特殊标记(如"_notEnter"可能是业务中用于跳过回车的标记)value = value.replace("_notEnter", "")time.sleep(0.5)  # 等待值更新# 核心断言:输入框的value属性中必须包含目标值assert (value in self.inputCtrl.getAttribute("value")), \f'元素html:{self.inputCtrl.get_inner_html()}期望值:{value},实际值:{self.inputCtrl.getAttribute("value")}'else:  # 空值校验# 严格匹配空字符串assert (data == self.inputCtrl.getAttribute("value")), \f'元素html:{self.inputCtrl.get_inner_html()}期望值:{data},实际值:{self.inputCtrl.getAttribute("value")}'

比较输入的预期值和输入控件(inputCtrl:具体的输入控件,文本框单选框啥的)实际输入的值

设计目的
输入操作后必须验证 “实际输入值” 与 “预期值” 一致,避免因页面延迟、输入失败等问题导致后续流程出错。

  • 支持单值和多值校验(通过列表);
  • 处理特殊业务标记(如_notEnter);
  • 包含重试和等待,应对页面渲染延迟。

四、获取值方法:text()—— 统一获取输入值

def text(self):"""获取控件当前的值(适配不同类型的输入元素)"""# 如果inputCtrl未初始化,自动查找(优先用inputCtrlLoc,失败则找span标签)if self.inputCtrl is None:try:self.inputCtrl = self.find_child(self.inputCtrlLoc)except:self.inputCtrl = self.find_child(Locator(By.XPATH, './/span', wait=1))# 处理单选框(radio)的特殊情况:复用RadioCtrl获取选中值type = self.inputCtrl.getAttribute('type')if type == 'radio':radio_ctrl = RadioCtrl.instance(self.get_parent())return radio_ctrl.text()else:# 普通输入框:优先取value属性;如果没有value(如span文本),取text()if self.inputCtrl.getAttribute('value') is None:return self.inputCtrl.text()return self.inputCtrl.getAttribute("value")

核心能力
统一不同输入元素的 “取值逻辑”,无论控件是inputtextarea还是radio,调用text()都能返回正确的值,简化子类和外部调用。

五、辅助方法

  1. is_this_ctrl:判断元素是否为输入控件

    @classmethod
    def is_this_ctrl(cls, ctrl_html):# 如果元素的HTML中包含"input",则认为是输入控件return "input" in ctrl_html
    
  2. enter:模拟回车键

    def enter(self):self.inputCtrl.sendKeys(Keys.ENTER)  # 向输入框发送回车键
    

    输入完成后常用的操作(如提交表单、触发搜索),父类统一实现避免重复代码。

六、作为父类的设计价值

InputCompBase的核心作用是 **“抽取输入控件的共性逻辑,统一标准”**,具体体现在:

  1. 减少重复代码:所有输入控件都需要定位元素、校验值,这些逻辑在父类中实现,子类只需关注自身特殊逻辑(如_input)。
  2. 统一操作标准:无论子类是文本框、单选框还是复合输入控件,都通过input()方法输入、text()方法取值,外部调用方式一致
  3. 增强可靠性:内置重试(@retry)、等待、断言等机制,解决页面不稳定问题,所有子类自动继承这些能力。

http://www.dtcms.com/a/363717.html

相关文章:

  • 解决HyperMesh许可证与版本不匹配问题
  • 【107】基于51单片机智能炒菜机【Proteus仿真+Keil程序+报告+原理图】
  • Vue + fetchEventSource 使用 AbortController 遇到的“只能中止一次”问题解析与解决方案
  • LeetCode 844.比较含退格的字符串
  • Spring 事务原理解析:AOP 的一次完美落地
  • 高校党建信息管理系统的设计与实现-(源码+LW+可部署)
  • wpf模板之DataTemplate
  • HTML第五课:求职登记表
  • apache-jmeter-5.1.1安装部署与使用教程(小白一看就会)​
  • Docker启动两个Redis镜像并配置一主一从
  • Spring Boot数据脱敏方案
  • sed相关知识
  • C++基础组件
  • 【值得收藏】手把手教你用PyTorch构建Transformer英汉翻译系统,从训练到推理
  • 小程序蓝牙低功耗(BLE)外围设备开发指南
  • C++革命性新特性:默认实例导出(exportDefault)让单例模式变得无比简单!
  • Vue2 入门(一)介绍及Demo项目创建
  • GISBox内置免费GIS服务器:地形服务发布与应用全指南
  • ChartView的基本使用
  • Redis 的压缩列表:像快递驿站 “紧凑货架“ 一样的内存优化结构
  • Redis-底层数据结构篇
  • 8.30美团技术岗算法第二题
  • 【C++】15. ⼆叉搜索树
  • WordPress.com 和 WordPress.org 之间的区别说明
  • 系统架构——过度设计
  • IO_HW_9_2
  • 教你 Centos 如何离线安装 rlwrap 插件(内网环境)
  • MATLAB矩阵及其运算(三)矩阵的创建
  • 一文搞懂:0-1整数规划与蒙特卡罗模拟(附MATLAB代码详解)
  • 命令行文本处理小工具:cut、sort、uniq、tr 详解与应用