Windows的识别属性
Windows平台上的控件识别依赖于一系列属性,这些属性帮助测试框架定位和操作界面元素。
一. 通用识别属性
通用识别属性是所有控件共有的,不依赖于特定控件类型的属性。
name
控件的内部名称,用于标识控件。
type
控件的类型,这是一个必需属性,影响控件提供的操作API。 例如:Button、Text、Window、List、Table、Tree等。
className
控件所属的类名称,源自控件在代码中的类定义。
例如,Qt中常用于窗口的控件是QWidget,因此窗口的type
为Window,而className
为QWidget,如图所示:
由于className
的值通常只与type
和应用使用的框架(Qt、WPF、WinForm等等)相关,所以有时可用于识别应用的技术栈。
automationId
一般来自.NET框架,是目标控件中用于自动化测试的一个属性,在官方文档中的解释为:
An ID for an element that is unique among siblings within its container.
相对于同一个容器中的兄弟姐妹们来说控件唯一的标识。
因此适用于.NET框架(比如WPF、WinForm等)应用和控件的自动化,对于其它类型的应用中的控件而言一般都是空值。
accessKey
目标控件的快捷键,与automationId
类似,都是用于自动化的一个属性,但通常为空值。
value
目标控件的值(通常是可变的值),并且与value
属性方法返回的结果相同。作为其它属性,可以手动将其添加为识别属性。
通常情况下,像value这种可变的属性并不是理想的识别属性,因为当控件的值发生改变后就会出现识别不到的问题。但是由于部分应用在开发过程中,会将可编辑的控件设置为不可编辑,在这个时候value就能够充当识别属性了。
appName
appName
属性存在于根节点窗口对象中,用来标识应用。它的值是可执行文件名不包含后缀的部分。例如Windows记事簿的可执行文件是"notepad.exe",那么识别记事簿应用的窗口对象时会获得appName="notepad"的属性值。
缺省情况下,appName在识别到以后不会作为标识属性,而是作为其他属性存在。如果发现应用程序的顶层窗口识别属性非常少,不足以唯一标识被测应用,可以手动把appName添加到标识属性中。
对于Electron应用,appName会有更重要的作用。因为Electron应用使用Chrome的实现,它的顶层窗口的识别属性类似于Chrome,另一方面,由于CukeTest也时使用Electron,在自动化时,使用appName属性,也有助于区分CukeTest和被测应用。因此在使用Windows侦测方式识别Electron应用界面时,会主动将appName作为标识属性。
二. 辅助识别属性
控件索引:index
index
属性用于指定目标控件在多个匹配控件中的位置,特别是在识别属性过少或不够唯一时,可以通过 index
来确定具体的控件。这里以模型管理器的 高亮 功能为例,说明一下识别到多个控件时的处理方式:
识别到多个控件时:当模型管理器/侦测器同时识别到多个控件(可能由于识别属性不够具体,或者应用中存在多个同名控件等情况),所有匹配到的控件会被以数组的形式返回。此时,index
属性可以帮助选择数组中的特定控件。例如,index = 0
时选择第一个控件,index = 1
时选择第二个,依此类推。同时,模型管理器会在左下方显示识别到的控件信息。
通常情况下,index
属性默认值为 0
,即始终选择第一个匹配控件。因此,即便只有一个控件被识别到,index = 0
也能正常使用,但若使用其他索引值(如 1
、2
),则会返回 错误1003:不能找到这个对象
。
当模型管理器发现同一个对象节点匹配到多个控件时,会在左下角显示当前匹配的第一个控件的坐标和总的匹配控件数量,如下图所示。这种情况说明当前对象节点未能通过唯一性验证,继续操作该节点可能会带来错误的结果。为解决这一问题,您可以使用“自动添加索引”功能,或者手动添加 index
属性。
index
属性的适用场景及局限性
index
属性在大多数场景下都适用,但它也有一定局限性。它的定位是基于控件返回的数组顺序,因此在控件布局不经常变化的应用中比较可靠。然而,对于布局或控件数量经常变化的应用(例如在 Qt 自动化中处理 List
和 Tree
控件时),index
属性的使用可能不够稳定。更多关于 index
在实际开发中的应用,您可以参考以下演练文档:
搜索提示:searchHint
searchHint
属性提供了一种帮助测试程序更快速、精准地找到目标控件的搜索提示信息,减少控件识别失败的可能性。当前支持的 searchHint
属性值包括 fromPoint
和 navigate
。
1. 基于坐标的控件搜索:fromPoint
fromPoint
是一种通过遍历控件区域中的坐标点来搜索子控件的方式,适用于那些在控件结构树中不可见但可以被检测到的控件(例如使用 ATL 或 DevExpress 技术开发的控件)。这些控件的特点通常是:它们可以被侦测到,但无法高亮显示,父控件下也看不到任何子控件(即 findControls()
返回空数组)。
当为控件指定了 fromPoint
属性后,执行时将改变默认的子控件搜索方式。通常情况下,程序会调用 UIA 的 FindAll
API 搜索子控件;但使用 fromPoint
时,程序会以 10 像素为间隔遍历控件区域,并通过坐标定位子控件。
何时使用 fromPoint
?
如果满足以下情况,可以考虑使用 fromPoint
属性:
- 某个控件在模型管理器中能被检测到,并且通过了唯一性验证,但保存后无法高亮显示(操作期间控件属性未发生变化,且应用未重启)。
- 在浏览控件树中查看时,父控件下未显示任何子控件(或者
findControls()
返回空数组)。
此时,您可以为该控件的父控件添加 fromPoint
属性,确保其子控件能够正确定位。
注意:
fromPoint
的行为自 CukeTest 1.8.3.108 版本起有所调整,以上说明适用于该版本及之后的版本。
2. 基于导航的控件搜索:navigate
navigate
属性通过使用导航方法来定位子控件,而不是依赖 UIA 的搜索 API。该方式适用于解决某些控件在定位时导致卡顿或 UIA 服务崩溃的问题,尤其在较旧的应用程序中更为常见。
使用 navigate
属性时,程序首先定位到当前控件的父控件,接着使用 firstChild()
和 next()
方法依次导航,直到找到符合条件的控件。
使用注意事项:
navigate
会忽略容器控件内的子控件(如listItem
、treeItem
、tableItem
)。在这些场景下,需要在item
控件的上层指定其容器,例如为listItem
指定list
作为容器。
以下是在描述模式中使用 navigate
定位 listItem
的示例代码:
listItem = WinAuto.getGeneric([
{
"type": "Window",
"automationId": "MainForm",
"appName": "ProgramName",
"searchHint": "navigate"
},
{
"type": "List",
"className~": "^WindowsForms10\\.SysListView32\\.app\\.",
"index": "2"
}, {
"type": "ListItem",
"automationId": "ListViewItem-6"
}
])
objectType
目标控件的抽象类型。objectType
是为了更精确地控制和操作这些控件而设计的一个属性。它允许我们告诉CukeTest应该如何理解和处理特定的控件,即使这个控件的原生类型 (type
或classType
) 在开发阶段已被确定。
以 Windows 11 的资源管理器为例,展示文件分组的控件类型被识别为 Group
,这意味着它们本身不提供直接获取数据的 data()
方法。但是,通过将这些控件的 objectType
设置为 List
,我们便能够按照列表控件的方式对它们进行操作,从而使用列表控件的所有方法和属性。
实际操作中,当我们将 objectType
设为 List
后,就可以在脚本中使用列表的相关操作,如下所示:
await model.getList("上月").data(); // 设置为List类型后,还可以使用List控件的智能提示,提升编码效率
model.getList("上月").data()
这种做法不仅增强了脚本的可读性,还通过智能提示功能加速了脚本的编写和调试过程。
levelToParent
目标控件的所处层次。对于多层次的应用来说,有时会出现目标控件存在同名的子控件或父控件,这个时候通过限制识别层级可以避免识别到不需要的控件,如下图所示:
三. 特有属性
特有属性是指只存在于某些特定类型控件的属性。
text
目标控件的文本内容,存在于Text控件中。
url
目标控件指向的链接,存在于Hyperlink控件中。
title
目标控件的标题,通常存在于Window控件中。
hWnd
目标控件的窗口句柄,只存在于Window控件中。
helpText
目标控件的帮助文字,大部分控件都有该属性,但常常为空。
processId
目标控件所处应用的进程标识,也就是PID,在描述模式中比较常用到。
四、其他属性
boundingRectangle
目标控件的形状信息,由一组长度为4的数组描述,数组中的值代表:[x, y, width, height]
,其中的x
和y
分别代表控件在桌面坐标系中的横纵坐标,width
和height
代表控件的宽度和高度。boundingRectangle
通常用于绘制控件的高亮框,由于应用窗口化启动时的大小和位置都不确定,boundingRectangle
就会十分不稳定,因此也极少作为识别属性使用。如果应用中的控件无法被很好的识别,必须要使用控件的坐标等信息作为操作目标,那么推荐使用虚拟控件作为解决方案。
appPath
类似于appName
属性,appPath
属性也只存在于顶层窗口对象中,它是被测应用首次被侦测到时的执行路径。不同的是,appPath
不能作为识别属性。它可以协助启动被测应用,如果根对象有这个属性,那么在这个对象上点击右键,弹出菜单中会出现"启动应用"的选项,选择这个选项会直接启动这个应用,前提是appPath的值能定位到这个执行文件。
在代码中使用识别属性
在一些情况下,我们可以跳过模型管理器直接在代码中通过识别属性来取得目标控件,这在很多情况下可以完成更加灵活的自动化,就像Qt的几个演练一样。而使用的就是findControls
方法,关于它的用法说明可以点击查看获取对象API。