第一次接触PC端自动化测试时,我面对着一台需要重复测试的财务软件发呆。每天要手动点击上百次按钮,填写几十张表单,这种重复劳动让我开始寻找自动化解决方案。经过多次尝试,我发现pywinauto、pywin32和pyautogui这三个Python库的组合,就像瑞士军刀一样能解决各种桌面自动化难题。
这三个库各有所长:pywinauto擅长应用程序和窗口管理,pywin32提供底层Windows API调用,pyautogui则专注于屏幕和输入设备控制。在实际项目中,我经常需要根据具体场景灵活搭配使用它们。比如测试一个ERP系统时,用pywinauto操作主界面控件,用pywin32处理弹出的消息框,再用pyautogui完成截图验证,三者配合天衣无缝。
安装这三个库非常简单,推荐使用清华源加速:
python复制pip install pywinauto pypiwin32 pyautogui -i https://pypi.tuna.tsinghua.edu.cn/simple
注意:安装pywin32时要使用pypiwin32这个包名,直接pip install pywin32可能会报错。
在我的自动化测试项目中,pywinauto的Application类是最常用的工具。它就像应用程序的遥控器,可以启动、连接和关闭任何Windows程序。记得第一次用它控制WPS时,我惊讶于只需几行代码就能完成整个文档处理流程。
启动应用程序有两种方式:
python复制from pywinauto.application import Application
# 方式一:通过完整路径启动
app = Application(backend="uia").start(r"C:\Program Files\WPS Office\ksolaunch.exe")
# 方式二:通过系统环境变量中的程序名启动
app = Application(backend="win32").start("notepad.exe")
连接已运行的应用程序也很重要,特别是在测试需要长时间运行的软件时:
python复制# 通过进程ID连接
app.connect(process=1234)
# 通过窗口标题连接
app.connect(title_re=".*WPS表格.*")
窗口控制是自动化测试的核心,pywinauto提供了丰富的窗口操作方法。有次测试一个多窗口应用时,我发现窗口标题会动态变化,这时就需要更灵活的定位方式。
窗口定位的多种姿势:
python复制# 通过类名和标题精准定位
main_window = app.window(class_name="Qt5QWindowIcon", title="WPS表格")
# 通过模糊匹配标题
window = app.window(title_re=".*报表.*")
# 通过索引访问
dialog = app.window(best_match="Dialog")[0]
获取窗口信息对调试非常有帮助:
python复制# 打印窗口所有控件树
main_window.print_control_identifiers()
# 获取窗口位置和大小
rect = main_window.rectangle()
print(f"窗口位置:左{rect.left}, 上{rect.top}, 右{rect.right}, 下{rect.bottom}")
控件操作是自动化测试中最容易出问题的环节。记得有次测试一个Java开发的客户端,标准方法怎么也定位不到控件,最后发现需要切换backend参数。
常见的控件操作示例:
python复制# 在WPS表格中输入数据
app.WPS表格.Edit.type_keys("2023年财务报表", with_spaces=True)
# 点击菜单项
app.WPS表格.menu_select("文件->另存为")
# 处理文件保存对话框
save_dialog = app.window(title="另存为")
save_dialog["文件名:Edit"].type_keys("report.xlsx")
save_dialog["保存(S)"].click()
踩坑提醒:遇到控件无法定位时,可以尝试切换backend参数为"uia",或者使用Inspect.exe工具查看控件实际属性。
当pywinauto无法满足某些特殊需求时,pywin32就派上用场了。它就像直接与Windows系统对话的接口,能实现更底层的操作。有次测试一个游戏客户端时,常规方法都无法获取其隐藏窗口,正是pywin32解决了这个问题。
窗口查找的多种方式:
python复制import win32gui
import win32con
# 查找顶层窗口
hwnd = win32gui.FindWindow("UnityWndClass", None)
# 查找子窗口
child_hwnd = win32gui.FindWindowEx(hwnd, 0, "UnityDropDown", None)
# 通过枚举所有窗口查找
def callback(hwnd, extra):
if "游戏大厅" in win32gui.GetWindowText(hwnd):
extra.append(hwnd)
windows = []
win32gui.EnumWindows(callback, windows)
窗口状态管理实战:
python复制# 最小化窗口
win32gui.ShowWindow(hwnd, win32con.SW_MINIMIZE)
# 恢复窗口
if win32gui.IsIconic(hwnd):
win32gui.ShowWindow(hwnd, win32con.SW_RESTORE)
# 置顶窗口
win32gui.SetWindowPos(hwnd, win32con.HWND_TOPMOST, 0,0,0,0,
win32con.SWP_NOMOVE | win32con.SWP_NOSIZE)
Windows的消息机制是GUI编程的核心,pywin32可以直接发送消息模拟用户操作。测试一个老旧VB程序时,正是通过直接发送消息解决了控件无法操作的问题。
常用消息操作示例:
python复制# 发送按键消息
win32gui.SendMessage(hwnd, win32con.WM_KEYDOWN, win32con.VK_RETURN, 0)
# 点击按钮(BN_CLICKED消息)
button_hwnd = win32gui.FindWindowEx(hwnd, 0, "Button", "确定")
win32gui.SendMessage(button_hwnd, win32con.BM_CLICK, 0, 0)
# 设置编辑框文本
edit_hwnd = win32gui.FindWindowEx(hwnd, 0, "Edit", None)
win32gui.SendMessage(edit_hwnd, win32con.WM_SETTEXT, 0, "测试内容")
pyautogui就像虚拟的眼睛和手,能"看到"屏幕内容并操作鼠标键盘。在测试一个没有控件信息的游戏界面时,图像识别成了唯一的解决方案。
屏幕操作实战代码:
python复制import pyautogui
# 获取屏幕信息
screen_width, screen_height = pyautogui.size()
print(f"屏幕分辨率:{screen_width}x{screen_height}")
# 智能等待图片出现
button_pos = pyautogui.locateCenterOnScreen('submit_button.png',
confidence=0.9,
minSearchTime=5)
if button_pos:
pyautogui.click(button_pos)
测试数据录入功能时,需要精确模拟各种输入操作。pyautogui提供了丰富的鼠标键盘控制方法。
输入设备控制示例:
python复制# 鼠标移动和点击
pyautogui.moveTo(100, 200, duration=0.5) # 缓慢移动更接近真人操作
pyautogui.doubleClick()
# 键盘输入
pyautogui.write("Hello World!", interval=0.1) # 模拟真人打字速度
pyautogui.hotkey('ctrl', 's') # 保存快捷键
# 拖拽操作
pyautogui.dragTo(300, 400, duration=1, button='left')
实用技巧:在关键操作前加入pyautogui.PAUSE = 1设置操作间隔,可以避免执行过快导致的问题。
让我们用一个完整案例展示三剑客如何协同工作。这个测试场景是:自动创建WPS文档,插入内容,保存并验证结果。
完整测试脚本:
python复制import time
import pyautogui
from pywinauto.application import Application
import win32gui
import win32con
# 启动WPS文字
app = Application(backend="uia").start("wps.exe")
# 使用pywinauto操作主界面
main_window = app.window(title_re=".*WPS文字.*")
main_window.wait('visible', timeout=10)
main_window.type_keys("这是自动化测试生成的内容{ENTER}")
# 使用pywin32处理可能的消息框
def close_popup():
hwnd = win32gui.FindWindow("#32770", "提示")
if hwnd:
win32gui.PostMessage(hwnd, win32con.WM_CLOSE, 0, 0)
# 使用pyautogui处理保存操作
main_window.menu_select("文件->另存为")
time.sleep(1) # 等待对话框出现
pyautogui.typewrite("test_document.docx")
pyautogui.press('enter')
# 验证结果
saved_file = pyautogui.locateOnScreen('saved_icon.png')
assert saved_file is not None, "文件保存验证失败"
# 清理
app.kill()
在实际项目中,我会将这些自动化操作集成到测试框架中。以下是几个实用建议:
python复制class WinAutoHelper:
@staticmethod
def wait_window(title, timeout=10):
"""等待窗口出现"""
start = time.time()
while time.time() - start < timeout:
hwnd = win32gui.FindWindow(None, title)
if hwnd: return hwnd
time.sleep(0.5)
raise TimeoutError(f"窗口{title}未在{timeout}秒内出现")
python复制def safe_click(element):
try:
element.click()
logging.info(f"成功点击元素:{element}")
except Exception as e:
logging.error(f"点击元素失败:{str(e)}")
raise
python复制def wait_for_image(image, timeout=30):
"""等待图片出现在屏幕上"""
start = time.time()
while time.time() - start < timeout:
pos = pyautogui.locateCenterOnScreen(image)
if pos: return pos
time.sleep(0.5)
return None