【GUI自动化测试】菜单控件操作与记事本自动化测试实践
文章目录
- 一、菜单控件的操作
- 1.1 items()
- 1.2 item_by_index()
- 1.3 item_by_path()
- 二、多层菜单选项的定位
- 2.1 menu_select()
- 2.2 ⾃动化测试场景⽰例:批量创建⽂件
- 🚩总结
一、菜单控件的操作
1.1 items()
返回对话框的菜单项,如果没有菜单项,则返回空列表
⽰例:获取菜单
app = Application(backend='uia').connect(process=29168)
win = app.window(title_re='.*Sublime Text.*')
win.wait( "visible")
menu = win['应用程序']for menu_item in menu.items():print(menu_item)
结果:
from pywinauto import Application# 连接窗口(以记事本为例,需根据实际进程/标题调整)
app = Application(backend='uia').connect(title_re=".*Notepad.*")
win = app.window(title_re=".*Notepad.*")
win.wait('visible')# 定位第一张图的菜单栏(标识包含 'Menu')
menu_bar = win['Menu']# 遍历菜单项(应输出“文件”“编辑”“查看”等)
for item in menu_bar.items():print(item)
1.2 item_by_index()
语法:item_by_index ( idx)
查找索引指定的菜单项
idx
:索引,从0开始
from pywinauto import Applicationapp = Application(backend='uia').connect(process=27176)
win = app.window(title_re=".*Notepad.*")
win.wait('visible')# 修正 found_index=0,定位顶部菜单栏(文件/编辑/查看)
menu_bar = win.child_window(auto_id="MenuBar",control_type="MenuBar",found_index=0 # 改为0,匹配顶部菜单栏
)# 再次确认菜单项数量
print("修正后菜单项数量:", len(menu_bar.items())) # 正常应为3(文件/编辑/查看)# 按索引访问(此时索引0、1、2有效)
file_menu = menu_bar.item_by_index(0) # 文件
edit_menu = menu_bar.item_by_index(1) # 编辑
view_menu = menu_bar.item_by_index(2) # 查看print("第0项(文件):", file_menu)
print("第1项(编辑):", edit_menu)
print("第2项(查看):", view_menu)
1.3 item_by_path()
语法:
item_by_path(path,exact=False)
用户查找路径指定的菜单项
path
:用于指定要选择的菜单项路径。
exact
:设置为True,则要求菜单项名称与路径中的名称完全匹配;
如果为False,则允许模糊匹配路径可以是“Menultem-> Menultem->Menultem …”形式的字符串,
其中每个Menultem是菜单该级别的项目文本。例如。
File->Export->ExportAsPNG
空格并不重要,所以你也可以写…
File -> Export -> Export As PNG
代码:
from pywinauto import Application# 连接记事本窗口(通过窗口标题匹配)
app = Application(backend='uia').connect(title_re=".*Notepad.*")
win = app.window(title_re=".*Notepad.*")
win.wait('visible') # 等待窗口可见# 定位顶部菜单栏(对应控件标识中的 'Menu')
menu_bar = win['Menu']# -------------------- 示例1:定位顶层菜单项“文件” --------------------
file_menu = menu_bar.item_by_path("文件")
print("通过 item_by_path 定位到的 '文件' 菜单项:", file_menu)# -------------------- 示例2:定位多层级菜单项(文件 -> 新建标签页) --------------------
try:# 步骤1:点击“文件”菜单,展开其子项(必须先展开,否则子菜单不可见)file_menu.click_input()# 步骤2:定位“文件 -> 新建标签页”(此时子菜单已展开,可被定位)new_tab_menu = menu_bar.item_by_path("文件->新建标签页")print("通过 item_by_path 定位到的 '文件->新建标签页' 菜单项:", new_tab_menu)
except Exception as e:print("定位多层级菜单项时出现错误:", e)# -------------------- 遍历所有顶层菜单项 --------------------
print("\n遍历顶部菜单栏的所有顶层菜单项:")
for item in menu_bar.items():print(item)
定位打开另存为:
from pywinauto import Application
from pywinauto.timings import wait_until
import time# 连接记事本窗口
app = Application(backend='uia').connect(title_re=".*Notepad.*")
win = app.window(title_re=".*Notepad.*")
win.wait('visible') # 等待主窗口可见# 定位顶部菜单栏
menu_bar = win['Menu']# 定位“文件”顶层菜单
file_menu = menu_bar.item_by_path("文件")
print("定位到 '文件' 菜单:", file_menu)try:# 步骤1:点击“文件”菜单,展开子菜单(模拟真实点击)file_menu.click_input()time.sleep(0.5) # 给菜单展开留时间(也可通过wait_until更严谨判断)# 步骤2:定位“文件->另存为”菜单项(确保子菜单已加载)save_as_menu = menu_bar.item_by_path("文件->另存为")print("定位到 '文件->另存为' 菜单项:", save_as_menu)# 步骤3:点击“另存为”菜单项(触发弹窗)save_as_menu.click_input()print("已点击 '另存为',等待弹窗出现...")# 步骤4:等待“另存为”窗口可见(验证弹窗触发成功)save_as_dialog = app.window(title="另存为")save_as_dialog.wait('visible', timeout=5)print("'另存为' 窗口已成功弹出")except Exception as e:print("操作失败:", e)
二、多层菜单选项的定位
点击文件,打开文件窗口,点击最近使用,会调起最近使用窗口,然后点击清除列表
以下是结合**「菜单路径定位」和「控件坐标微调点击」**的两种方法完整代码:
方法一:通过 item_by_path
菜单路径直接操作
from pywinauto import Application
import time# 1. 连接记事本窗口
app = Application(backend='uia').connect(title_re=".*Notepad.*")
win = app.window(title_re=".*Notepad.*")
win.wait('visible') # 等待窗口可见try:# 2. 定位顶部菜单栏menu_bar = win['Menu'] # 3. 展开「文件」菜单file_menu = menu_bar.item_by_path("文件")file_menu.click_input() time.sleep(0.5) # 给菜单展开留延迟# 4. 展开「最近使用」子菜单recent_menu = menu_bar.item_by_path("文件->最近使用")recent_menu.click_input() time.sleep(0.5) # 给子菜单展开留延迟# 5. 在「最近使用」的子菜单上下文中,定位并点击「清除列表」clear_menu = recent_menu.item_by_path("清除列表") # 注意:在recent_menu上下文内定位clear_menu.click_input()print("方法一:已通过「菜单路径」点击「清除列表」~")except Exception as e:print("方法一执行失败:", e)time.sleep(1) # 等待菜单状态重置,避免干扰方法二
方法二:通过「控件定位 + 坐标微调」点击
from pywinauto import Application
from pywinauto.mouse import move, click
import time# 1. 连接记事本窗口(若已连接可复用,此处重新连接确保环境干净)
app = Application(backend='uia').connect(title_re=".*Notepad.*")
win = app.window(title_re=".*Notepad.*")
win.wait('visible')try:# 2. 先展开「文件->最近使用」菜单(确保「清除列表」控件可见)file_menu = win['Menu'].item_by_path("文件")file_menu.click_input()time.sleep(0.5)recent_menu = win['Menu'].item_by_path("文件->最近使用")recent_menu.click_input()time.sleep(0.5)# 3. 定位「清除列表」控件(通过标题和控件类型)clear_item = win.child_window(title="清除列表", control_type="MenuItem")# 4. 获取控件矩形区域,计算中间点并微调坐标(解决点击偏差)rect = clear_item.rectangle()mid_point = rect.mid_point()click_coord = (mid_point.x, mid_point.y + 30) # 微调 y 坐标(根据实际偏差调整数值)# 5. 模拟鼠标移动 + 点击move(click_coord) # 移动鼠标到目标坐标time.sleep(0.5) # 鼠标移动后等待稳定click(click_coord) # 执行点击print("方法二:已通过「控件定位 + 坐标微调」点击「清除列表」~")except Exception as e:print("方法二执行失败:", e)
2.1 menu_select()
语法: menu_select(path,exact=False)
用户查找路径指定的菜单项
path
:用于指定要选择的菜单项路径。
exact
∶设置为True,则要求菜单项名称与路径中的名称完全匹配;如果为False,则允许模糊匹配
注意,
menu_select()
的使用和上面有区别,使用menu_select()的场景下,通常至少有两个菜单栏:“系统”和“应用程序”系统菜单栏是一个标准的窗口菜单,包含以下项目:“还原”、“移动”、“大小”、“最小化”等。此菜单栏通常有一个“标题栏”控件作为父级。应用程序菜单栏通常是我们要找的。在大多数情况下,它的父级是对话框本身,因此可以在对话框的直接子级中找到它。
路径可以是“Menultem-> Menultem->Menultem ...”
形式的字符串,其中每个Menultem
是菜单该级别的项目文本。例如。
File->Export->ExportAsPNG
空格并不重要,所以你也可以写…
File -> Export -> Export As PNG
要使用 pywinauto
的 menu_select
方法操作菜单,核心是按照「层级路径格式」传递菜单路径(支持紧凑/带空格两种写法)。以下是结合截图示例的完整代码与说明:
示例:操作 Sublime Text 的「File -> Save」菜单
from pywinauto import Application# 1. 连接 Sublime Text 窗口(通过窗口标题匹配,也可改用进程ID)
app = Application(backend='uia').connect(title_re=r'.*Sublime Text.*')
win = app.window(title_re=r'.*Sublime Text.*')
win.wait('visible') # 等待窗口变为可见状态# 2. 方式1:紧凑路径(无空格,用 -> 连接)
win.menu_select(path="File->Save")
print("已通过「紧凑路径」执行 File->Save 操作")# (可选)给菜单操作留响应时间
import time
time.sleep(1)# 3. 方式2:带空格路径(更易读,用 -> 连接)
win.menu_select(path="File -> Save")
print("已通过「带空格路径」执行 File -> Save 操作")
扩展:操作多层级菜单(如「File->Export->Export As PNG」)
若要执行更复杂的菜单路径(如截图中的“导出为 PNG”),只需修改 path
参数:
# 多层级菜单示例
win.menu_select(path="File->Export->Export As PNG")
# 或带空格格式:
# win.menu_select(path="File -> Export -> Export As PNG")
print("已执行「File->Export->Export As PNG」菜单操作")
2.2 ⾃动化测试场景⽰例:批量创建⽂件
1)⽤例设计
2)代码实现
以⽤例“验证保存⽂件后,⽂件是否正确写⼊到指定路径。”为例
from pywinauto import Application
import time
import os
# 1. 启动并连接记事本
app = Application(backend='uia').start("notepad.exe") # 启动记事本
win = app.window(title_re=r'.* - 记事本') # 匹配“无标题 - 记事本”等窗口标题
win.wait('visible') # 等待窗口完全显示# 2. 批量创建文件(示例:创建2个文件)
for i in range(1, 3):# ① 向记事本编辑区输入内容content = f"这是第 {i} 个记事本文件的内容\n"win.type_keys(content)# ② 触发“文件 -> 另存为”菜单win.menu_select("文件->另存为")# ③ 等待“另存为”窗口出现save_win = app.window(title="另存为")save_win.wait('visible')# ④ 输入目标文件名(需确保保存路径存在,否则会报错)save_path = r"D:\file\GUITest" # 替换为实际存在的路径filename = os.path.join(save_path, f"test_{i}.txt")filename_edit = save_win.child_window(title="文件名:", control_type="Edit")filename_edit.type_keys(filename)# ⑤ 点击“保存”按钮save_btn = save_win.child_window(title="保存(S)", control_type="Button")save_btn.click_input()# ⑥ 验证文件是否成功创建time.sleep(1) # 等待文件写入磁盘assert os.path.exists(filename), f"文件 {filename} 创建失败!"print(f" 第 {i} 个文件 {filename} 已成功创建")# ⑦ 新建空白记事本(为下一次循环做准备)win.menu_select("文件->新建")new_win = app.window(title="无标题 - 记事本")new_win.wait('visible')win = new_win # 切换到新的空白记事本窗口# 最后关闭窗口
win.close()