前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >PC 自动化测试入门 - pywinauto 上篇:初识

PC 自动化测试入门 - pywinauto 上篇:初识

原创
作者头像
Lorin 洛林
修改2024-04-27 10:34:56
26600
代码可运行
修改2024-04-27 10:34:56
举报
文章被收录于专栏:Python 技术小屋Python 技术小屋
运行总次数:0
代码可运行

前言

  • 在软件开发领域,自动化测试是一项重要的实践,它可以提高测试效率、减少人力成本,并确保软件质量。PC 自动化测试特指针对 Windows 平台的应用程序进行自动化测试,而 pywinauto 是一款用于实现 Windows GUI 应用程序自动化测试的 Python 库。本文将介绍 PC 自动化测试的基本概念、常用工具以及初识 pywinauto,以及通过一个操作记事本的示例演示其基本用法。

PC 自动化测试 是什么?

  • PC 自动化测试是指利用自动化工具或脚本来模拟用户操作,对 Windows 平台的应用程序进行功能测试、性能测试等,以验证其是否符合预期行为。相比手动测试,自动化测试可以提高测试效率、减少测试成本,并且可以在持续集成和持续交付流程中实现自动化测试。

常用 PC 自动化测试工具

  • 在 PC 自动化测试领域,有许多常用的工具,如:
代码语言:txt
复制
- Selenium:用于 Web 应用程序的自动化测试。
- pywinauto:用于 Windows GUI 应用程序的自动化测试。
- AutoIt:用于 Windows 平台的自动化测试,支持模拟键盘和鼠标操作。

pywinauto 是什么?

  • pywinauto 是一款基于 Python 的开源库,用于自动化测试 Windows 平台的 GUI 应用程序。它能够模拟用户的键盘和鼠标操作,以及获取和修改应用程序的控件属性。pywinauto 提供了简单而强大的 API,使得开发人员可以轻松地编写自动化测试脚本。

Windows上支持的可访问性技术列表

  • 一旦你安装了pywinauto,第一件必要的事情是确定您的应用程序可以使用哪种可访问性技术(pywinauto的后端)。常用的有 Win32 API、MS UI。
  • 如果你不知道程序到底适用于那种可访问技术,可以借助于GUI对象检查工具来做,常用的检查工具有Inspect.exe,Spy++ 等,下面以 Inspect.exe 为例:

操作记事本自动写入

  • 环境:win 10、Python 3.12
代码语言:Python
复制
from pywinauto import Application

# 连接 PC 应用的两种方式
# app = Application(backend="uia").start("notepad.exe")
app = Application(backend="uia").connect(process=32120)

print(app.process)

# 获取主窗口
top_window = app.window(title="无标题 - Notepad", control_type="Window")
# 打印控件菜单树结构
top_window.print_control_identifiers()

# 获取输入框
document = top_window.child_window(control_type="Document")

document.print_control_identifiers()
# 标出是否正确选中输入框
document.draw_outline(colour='red')

# 写入
document.click_input()
document.type_keys(keys="Your text here", with_spaces=True)
  • 输出结果:
代码语言:txt
复制
32120
Control Identifiers:

Dialog - '无标题 - Notepad'    (L-1512, T194, R-192, B886)
['Dialog', '无标题 - NotepadDialog', '无标题 - Notepad']
child_window(title="无标题 - Notepad", control_type="Window")
   | 
   | Pane - ''    (L-1505, T280, R-199, B879)
   | ['Pane', '无标题Pane', 'Pane0', 'Pane1', '无标题Pane0', '无标题Pane1']
   |    | 
   |    | Document - ''    (L-1505, T280, R-199, B879)
   |    | ['Document', '无标题Document']
   | 
   | Pane - ''    (L-1459, T205, R-1173, B237)
   | ['Pane2', '无标题Pane2']
   |    | 
   |    | TabControl - ''    (L-18704, T-17045, R-1129, B241)
   |    | ['TabControl', 'TabControl添加新标签页']
   |    | child_window(auto_id="Tabs", control_type="Tab")
   |    |    | 
   |    |    | ListBox - ''    (L-18704, T-17045, R-1169, B241)
   |    |    | ['ListBox']
   |    |    | child_window(auto_id="TabListView", control_type="List")
   |    |    |    | 
   |    |    |    | TabItem - '无标题. 未修改。'    (L-1455, T205, R-1173, B241)
   |    |    |    | ['无标题. 未修改。TabItem', '无标题. 未修改。', 'TabItem']
   |    |    |    | child_window(title="无标题. 未修改。", control_type="TabItem")
   |    |    |    |    | 
   |    |    |    |    | Static - '无标题'    (L-1440, T214, R-1398, B232)
   |    |    |    |    | ['Static', '无标题', '无标题Static']
   |    |    |    |    | child_window(title="无标题", control_type="Text")
   |    |    |    |    | 
   |    |    |    |    | Button - '关闭标签页'    (L-1219, T209, R-1183, B236)
   |    |    |    |    | ['Button', '关闭标签页', '关闭标签页Button', 'Button0', 'Button1']
   |    |    |    |    | child_window(title="关闭标签页", auto_id="CloseButton", control_type="Button")
   |    |    | 
   |    |    | Button - '添加新标签页'    (L-1166, T210, R-1130, B237)
   |    |    | ['Button2', '添加新标签页Button', '添加新标签页']
   |    |    | child_window(title="添加新标签页", auto_id="AddButton", control_type="Button")
   |    | 
   |    | Pane - '记事本自动保存进度。下次打开记事本时,你的所有内容都将可用。'    (L0, T0, R0, B0)
   |    | ['记事本自动保存进度。下次打开记事本时,你的所有内容都将可用。Pane', '记事本自动保存进度。下次打开记事本时,你的所有内容都将可用。', 'Pane3']
   |    | child_window(title="记事本自动保存进度。下次打开记事本时,你的所有内容都将可用。", auto_id="TeachingTip", control_type="Pane")
   | 
   | Pane - ''    (L-1505, T242, R-365, B275)
   | ['Pane4', '无标题Pane3']
   |    | 
   |    | Menu - ''    (L-1505, T242, R-1310, B278)
   |    | ['Menu', '无标题Menu', 'Menu0', 'Menu1']
   |    | child_window(auto_id="MenuBar", control_type="MenuBar")
   |    |    | 
   |    |    | MenuItem - '文件'    (L-1500, T242, R-1444, B278)
   |    |    | ['文件', '文件MenuItem', 'MenuItem', 'MenuItem0', 'MenuItem1']
   |    |    | child_window(title="文件", auto_id="File", control_type="MenuItem")
   |    |    | 
   |    |    | MenuItem - '编辑'    (L-1435, T242, R-1380, B278)
   |    |    | ['编辑', '编辑MenuItem', 'MenuItem2']
   |    |    | child_window(title="编辑", auto_id="Edit", control_type="MenuItem")
   |    |    | 
   |    |    | MenuItem - '查看'    (L-1370, T242, R-1314, B278)
   |    |    | ['查看', '查看MenuItem', 'MenuItem3']
   |    |    | child_window(title="查看", auto_id="View", control_type="MenuItem")
   |    | 
   |    | Button - '设置'    (L-237, T243, R-203, B277)
   |    | ['Button3', '设置', '设置Button']
   |    | child_window(title="设置", auto_id="SettingsButton", control_type="Button")
   | 
   | TitleBar - ''    (L0, T0, R0, B0)
   | ['TitleBar']
   |    | 
   |    | Menu - '系统'    (L-1503, T203, R-1478, B228)
   |    | ['Menu2', '系统', '系统Menu', '系统0', '系统1']
   |    | child_window(title="系统", auto_id="MenuBar", control_type="MenuBar")
   |    |    | 
   |    |    | MenuItem - '系统'    (L-1503, T203, R-1478, B228)
   |    |    | ['MenuItem4', '系统MenuItem', '系统2']
   |    |    | child_window(title="系统", control_type="MenuItem")
   |    | 
   |    | Button - '最小化'    (L-356, T195, R-303, B229)
   |    | ['Button4', '最小化Button', '最小化']
   |    | child_window(title="最小化", control_type="Button")
   |    | 
   |    | Button - '最大化'    (L-303, T195, R-251, B229)
   |    | ['Button5', '最大化', '最大化Button']
   |    | child_window(title="最大化", control_type="Button")
   |    | 
   |    | Button - '关闭'    (L-251, T195, R-198, B229)
   |    | ['Button6', '关闭', '关闭Button']
   |    | child_window(title="关闭", control_type="Button")
Control Identifiers:

Document - ''    (L-1505, T280, R-199, B879)
['Document']

问题

app = Application(backend="uia").start("notepad.exe") 无法正常启动

代码语言:Python
复制
app = Application(backend="uia").start("notepad.exe")
print(app.process)

打印的进程ID为 2643,但实际进程ID为 836,导致无法查找到元素:
pywinauto.findwindows.ElementNotFoundError: {'title': '无标题 - Notepad', 'control_type': 'Window', 'backend': 'uia', 'process': 21300}

有知道朋友可以帮忙解答一下,十分感谢

组件选择器和 print_control_identifiers 打印的组件不匹配

  • 使用了几个组件选择器:Inspect.exe、Spy++,感觉 Inspect.exe 最好用,但组件选择器和组件树不匹配,需要以打印的组件树为准。
  • 比如上面 demo 中关于输入框组件:
  • 组件树的打印结果:
代码语言:txt
复制
   |    | Document - ''    (L-1505, T280, R-199, B879)
   |    | ['Document', '无标题Document']
  • Inspect.exe 的结果:
  • Inspect.exe 的结果中有 name 字段,但实际上组件并没有 name,使用 name 会导致组件无法匹配到。

多个相同组件定位问题

  • 当使用 child_window 方法查找组件元素时,我们使用单一条件可能查到到多个组件,我们可以使用多个条件来尽可能确定唯一元素,比如下面这些条件:

参考

个人简介

? 你好,我是 Lorin 洛林,一位 Java 后端技术开发者!座右铭:Technology has the power to make the world a better place.

? 我对技术的热情是我不断学习和分享的动力。我的博客是一个关于Java生态系统、后端开发和最新技术趋势的地方。

? 作为一个 Java 后端技术爱好者,我不仅热衷于探索语言的新特性和技术的深度,还热衷于分享我的见解和最佳实践。我相信知识的分享和社区合作可以帮助我们共同成长。

? 在我的博客上,你将找到关于Java核心概念、JVM 底层技术、常用框架如Spring和Mybatis 、MySQL等数据库管理、RabbitMQ、Rocketmq等消息中间件、性能优化等内容的深入文章。我也将分享一些编程技巧和解决问题的方法,以帮助你更好地掌握Java编程。

? 我鼓励互动和建立社区,因此请留下你的问题、建议或主题请求,让我知道你感兴趣的内容。此外,我将分享最新的互联网和技术资讯,以确保你与技术世界的最新发展保持联系。我期待与你一起在技术之路上前进,一起探讨技术世界的无限可能性。

? 保持关注我的博客,让我们共同追求技术卓越。

我正在参与2024腾讯技术创作特训营最新征文,快来和我瓜分大奖!

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • PC 自动化测试 是什么?
  • 常用 PC 自动化测试工具
  • pywinauto 是什么?
    • Windows上支持的可访问性技术列表
    • 操作记事本自动写入
      • 问题
        • app = Application(backend="uia").start("notepad.exe") 无法正常启动
        • 组件选择器和 print_control_identifiers 打印的组件不匹配
        • 多个相同组件定位问题
    • 参考
    • 个人简介
    相关产品与服务
    云数据库 MySQL
    腾讯云数据库 MySQL(TencentDB for MySQL)为用户提供安全可靠,性能卓越、易于维护的企业级云数据库服务。其具备6大企业级特性,包括企业级定制内核、企业级高可用、企业级高可靠、企业级安全、企业级扩展以及企业级智能运维。通过使用腾讯云数据库 MySQL,可实现分钟级别的数据库部署、弹性扩展以及全自动化的运维管理,不仅经济实惠,而且稳定可靠,易于运维。
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
    http://www.vxiaotou.com