1.自动化流程
1.在handles和pageObject中封装方法
1.把所有元素都先定义为None,这样只需要传输唯一元素即可,不需要传递所有元素,减少代码的冗余
封装元素定位方法:
def locate_element(
self,
class_name=None,
class_name_re=None,
title=None,
title_re=None,
control_type=None,
best_match=None,
auto_id=None,
found_index=0):
"""
封装所有pywinauto定位元素的方法\n
class_name=None, # 类名\n
class_name_re=None, # 正则匹配类名\n
title=None, # 控件的标题文字,对应inspect中Name字段\n
title_re=None, # 正则匹配文字\n
control_type=None, # 控件类型,inspect界面LocalizedControlType字段的英文名\n
best_match=None, #\n
auto_id=None, # 这个也是固定的可以用,inspect界面AutomationId字段,但是很多控件没有这个属性
"""
try:
element = self.driver.child_window(class_name=class_name,
class_name_re=class_name_re,
title=title,
title_re=title_re,
control_type=control_type,
best_match=best_match,
auto_id=auto_id,
found_index=found_index).wait('visible')
element.draw_outline(colour="green", thickness=5)
except Exception as e:
element = None
self.log.info(e)
self.log.error(inspect.currentframe().f_back.f_code.co_name + " 元素定位输入有误")
return element
2.通过调用封装的元素定位方法,进行调用
一个测试用例示例:
# 下述文件应该放置在页面对象定义中,封装了页面元素的定位和操作方法,如:pageObject目录下
# 控件定位
def clear_machine_loc(self):
"""
获取清机元素
"""
return self.locate_element(title='清机')
def clear_machine_yes_loc(self):
"""
获取清机确定元素
"""
return self.locate_element(auto_id='PageBase.widgetMain.CashierWidget.SFMessageForm.btnOk')
def text_clear_machine_tips_loc(self):
"""
获取清机提示文本
"""
return self.clear_machine_tips_loc().window_text()
def clear_machine_no_loc(self):
"""
获取清机取消元素
"""
return self.locate_element(auto_id='PageBase.widgetMain.CashierWidget.SFMessageForm.btnCancel')
# 下述文件应该放置在页面操作处理文件夹中 如:handlers目录下
# 调用控件方法,执行操作
def click_clear_machine_loc(self):
"""
点击清机按钮
"""
self.clear_machine_loc().click_input()
def click_clear_machine_yes_lco(self):
"""
点击确定按钮
"""
self.clear_machine_yes_loc().click_input()
def text_clear_machine_tips_loc(self):
"""
获取清机提示文本
"""
return self.clear_machine_tips_loc().window_text()
def click_clear_machine_no_lco(self):
"""
点击取消按钮
"""
self.clear_machine_no_loc().click_input()
#下述文件应该放置在测试用例中,将手动操作的步骤代码化 如:testCase目录下
# 执行测试用例
@allure.story("操作清机") # 标记当前测试用例对应的用户故事或测试场景
@allure.title("清机_确认") # 当前测试用例在报告中显示的标题名称
@allure.description("该用例检查用户确认清机操作") # 为测试用例添加描述信息,说明该用例的测试目的
# 为测试用例添加一个可点击的外部链接,通常指向测试管理系统中的手工用例
@allure.testcase(
"手工用例url地址",
name="点击,跳转到对应用例的链接地址")
# 标明当前用例的执行优先级
@pytest.mark.p0
def test_clear_machine_forward(self):
# 步骤1:点击清机按钮
with allure.step('点击清机按钮'):
self.mph.click_clear_machine_loc()
# 记录当前时间,用于后续校验
current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
# 步骤2:点击确定按钮
with allure.step('点击确定'):
self.mph.click_clear_machine_yes_lco()
# 步骤3:再次点击清机按钮
with allure.step('再次点击清机按钮'):
self.mph.click_clear_machine_loc()
# 步骤4:校验清机是否成功
with allure.step('校验是否已清机成功'):
assert current_time in self.mph.text_clear_machine_tips_loc()
# 最后一步:点击取消按钮,退出清机界面
self.mph.click_clear_machine_no_lco()
3.执行断言,验证输出的结果
4.输出测试结果,通过或者失败
2.所有控件类型:
Button(按钮)
Calendar(日历)
CheckBox(复选框)
ComboBox(组合框 / 下拉框)
Custom(自定义控件)
DataGrid(数据网格)
DatePicker(日期选择器)
Dialog(对话框)
Document(文档控件)
Edit(编辑框 / 文本框)
GroupBox(组框)
Header(头部控件)
Hyperlink(超链接)
Image(图像控件)
Label(标签 / 静态文本)
ListBox(列表框)
ListView(列表视图)
Menu(菜单)
MenuBar(菜单栏)
MenuItem(菜单项)
Pane(窗格)
PopupMenu(弹出菜单)
ProgressBar(进度条)
RadioButton(单选框)
ScrollBar(滚动条)
Separator(分隔符)
Slider(滑块)
Spinner(微调器 / 数字增减控件)
SplitButton(分割按钮)
StatusBar(状态栏)
TabControl(选项卡控件)
TabItem(选项卡项)
Table(表格)
Text(文本控件)
Thumb(滑块拇指)
TitleBar(标题栏)
ToolBar(工具栏)
ToolTip(工具提示)
Tree(树状视图)
TreeItem(树节点)
Window(窗口)
3.鼠标操作
click() #单击鼠标某个键
double_click() #双击鼠标某个键
right_click() #单击鼠标右键
move() #移动鼠标
press() #按下鼠标
release() #放开鼠标
scroll() #滚动鼠标滚轮
wheel_click() #单击鼠标滚轮
4.遍历展示所有界面元素
from pywinauto.findwindows import find_elements
els=find_elements(backend='uia')
for el in els:
print(el)
5.打印的内容
uia_element_info.UIAElementInfo - '', SoPY_Status
uia_element_info.UIAElementInfo - '任务栏', Shell_TrayWnd
uia_element_info.UIAElementInfo - 'WeMail', Qt51517QWindowToolSaveBits
uia_element_info.UIAElementInfo - 'test.py - webuiauto - Visual Studio Code', Chrome_WidgetWin_1
uia_element_info.UIAElementInfo - 'linux命令', Chrome_WidgetWin_1
uia_element_info.UIAElementInfo - 'ProcessExplorer', CabinetWClass
6.连接并打印窗口所有元素
# 连接窗口
app = Application(backend='uia').connect(title="linux命令")
# 定位到linux命令窗口
dlg = app.window(title="linux命令")
# 打印窗口的所有元素
dlg.print_control_identifiers()
7.以fiddler为例
from pywinauto.application import Application
from pywinauto.findwindows import find_elements
import time
#获取当前所有窗口
els = find_elements(backend='uia')
print(els)
# 打开/链接fiddler工具
# app = Application(backend='uia').start('C:/Program Files (x86)/Fiddler2/Fiddler.exe')
app = Application(backend='uia').connect(title_re='Progress Telerik Fiddler web Debugger')
#获取窗口
dlg = app.window(title_re='Progress Telerik Fiddler web Debugger')
#点击停止抓包
# dlg.child_window(title_re='.*停止.*', control_type="Button").click()
el = dlg.child_window(best_match='Capturing')
el.click_input()
# 点击导出数据包
dlg.menu_select('File->Export Sessions')#菜单定位只能定位下级,无法定位下下级
# 子菜单选择,选择所有数据包
menu_item = app.window(best_match='All Sessions...')
menu_item.select()
#选择数据包格式
com = dlg.child_window(best_match='ComboBox')
com.click_input()
com_list = dlg.child_window(best_match='ComboBox')
com_list.click_input()
#点击next
com_list = dlg.child_window(best_match='Next')
com_list.click_input()
#文件对话框输入文件名
dlg.child_window(best_match='Text').set_text('flddler文件')
#点击保存
dlg.child_window(title='保存(S)').click_input()
8.PID定位未打开的软件,执行操作
import logging
from pywinauto import Application
import time
# 设置日志格式
logging.basicConfig(level=logging.INFO, format='[%(asctime)s] %(levelname)s: %(message)s')
# 启动语雀应用
app = Application(backend='uia').start(r"D:\yuque\语雀.exe")
# 等待应用启动
time.sleep(5)
# 获取 ProcessId
pid = app.process
print(f"语雀PID: {pid}")
# 通过 ProcessId 连接主窗口
app = Application(backend='uia').connect(process=pid)
main_window = app.window(title_re=".*py.*", control_type="Pane") # 需要一个关键词去做定位
main_window.wait("exists enabled visible", timeout=10) # 确保窗口可见可用
print("[成功] 已找到语雀主窗口")
# 定位并点击“fiddler使用说明”控件
try:
fiddler_link = main_window.child_window(title_re=".*fiddler使用说明.*", control_type="Hyperlink")
fiddler_link.wait("exists enabled visible", timeout=5)
fiddler_link.invoke()
print("[成功] 已点击“fiddler使用说明”控件")
time.sleep(3)
except Exception as e:
print(f"[错误] 无法点击“fiddler使用说明”控件: {e}")
# 定位并点击“sql”控件
try:
use_case_link = main_window.child_window(title_re=".*sql.*", control_type="Hyperlink")
print("[成功] 已找到“sql”控件")
use_case_link.wait("exists enabled visible", timeout=5)
use_case_link.invoke()
print("[成功] 已点击“sql”控件")
except Exception as e:
print(f"[错误] 无法点击“sql”控件: {e}")
9.通过任务管理器找到对应软件的handle进行连接操作
import logging
from pywinauto.findwindows import find_elements
from pywinauto.application import Application
import psutil
# 设置日志格式
logging.basicConfig(level=logging.INFO, format='[%(asctime)s] %(levelname)s: %(message)s')
def find_window_by_process_name(process_name, backend='uia'):
"""
通过进程名(如 语雀.exe)查找窗口,适用于 Electron 应用
"""
windows = find_elements(backend=backend)
for win in windows:
try:
p = psutil.Process(win.process_id)
if p.name() == process_name:
return win
except psutil.NoSuchProcess:
continue
return None
# 主流程,此处填写需要连接的进程名
win_info = find_window_by_process_name('语雀.exe', backend='uia')
if win_info:
print(f"窗口名称: {win_info.name}")
print(f"PID: {win_info.process_id}")
print(f"Handle: {win_info.handle}")
# 连接窗口
app = Application(backend='uia').connect(handle=win_info.handle)
main_window = app.window(handle=win_info.handle)
main_window.set_focus()
main_window.print_control_identifiers()
print("[成功] 已连接到语雀窗口")
else:
raise Exception("未找到语雀窗口,请确认语雀已启动")
# 定位并点击“fiddler”控件
try:
fiddler_link = main_window.child_window(title_re=".*fiddler.*", control_type="Hyperlink")
# link = dlg.child_window(title_re=".*fiddler.*", control_type="Hyperlink")
print("[成功] 已找到“fiddler”控件")
fiddler_link.wait("exists enabled visible", timeout=5)
print("[成功] 已等待“fiddler”控件")
# fiddler_link.click_input()
fiddler_link.invoke()
print("[成功] 已点击“fiddler”控件")
except Exception as e:
print(f"[错误] 无法点击“fiddler”控件: {e}")
# 定位并点击“sql”控件
try:
use_case_link = main_window.child_window(title_re=".*sql.*", control_type="Hyperlink")
use_case_link.wait("exists enabled visible", timeout=5)
use_case_link.invoke()
print("[成功] 已点击“sql”控件")
except Exception as e:
print(f"[错误] 无法点击“sql”控件: {e}")