1. 为什么Windows自动化会选Airtest做Windows桌面端的自动化测试我一开始其实没打算用Airtest。原因是这个工具在游戏测试、App测试圈子里更出名大家的印象里它就是个连手机、点模拟器的脚本工具。但等我真正在Windows系统上完成安装、跑通第一批用例之后我的判断变了这套工具在Windows桌面自动化场景里的表现被严重低估了。这篇教程就围绕Airtest在Windows系统上的安装、使用和实际用例展开把我在真实项目里踩过的坑和验证过的做法都写出来。我负责的产品是一个Windows桌面客户端每周发一版手工回归要花大半天。刚开始想用录制回放类工具脚本录完过两天界面一变就全废后来试过几种控件识别方案识别原生控件没问题但遇到自绘界面、嵌入Web页面和第三方组件时就抓瞎。最后Airtest进入视野是因为它默认基于图像识别界面怎么画它不管只要能截图、能找到目标图就能点击和断言。这个思路恰好绕开了Windows自绘UI的识别难题。1.1 一次真实的自动化回归需求项目背景是这样的Windows客户端包含登录、工作台、任务列表、设置中心几个模块其中任务列表里大量元素不是原生控件而是用自绘技术渲染出来的。用传统控件自动化工具去拿控件树拿到的要么是空白要么是几个无关节点根本定位不到按钮。手工测试则每天重复点同样的位置随着版本更新按钮坐标常常偏移几个像素整个用例就崩了。后来我们转变思路不用控件坐标改用图像特征定位。也就是说先把要点击的按钮截图保存下来脚本运行时在屏幕上寻找这张小图找到之后把这个按钮的实际中心点算出来再执行点击。这个思路下哪怕按钮位置变了只要外观变化不大脚本依然能跟上。Airtest的核心能力恰好就是这个它把截图定位、模拟点击、图像断言都封装成了现成API比从零写OpenCV匹配要快得多。1.2 几个主流方案的横向对比在定下Airtest之前我实际对比了好几个工具包括Appium、Pywinauto、TestComplete以及一些商业录制工具。每家的强项不一样适合的场景也不一样。Appium跨平台生态完整移动端能力强但Windows桌面端支持需要额外的WinAppDriver配置繁琐对自绘UI依然无能为力。Pywinauto对Windows原生控件识别很准适合传统Win32和部分Qt应用但纯图像定位能力基本没有遇到自绘UI就难以下手。TestComplete功能全面质量也好但价格高且学习曲线陡个人和中小团队很难直接上。Airtest图像识别是第一优先级也支持Poco控件树Windows端可以通过AirtestIDE一键连接还能生成带截图的HTML报告算是覆盖了自动化测试的完整闭环。我最终的选择逻辑很简单优先要能解决自绘UI定位问题的方案其次要上手够快、能出报告、能对接命令行。Airtest在这几个维度的平衡是最好的。1.3 Airtest的适用边界任何工具都有自己的边界Airtest也不是万能药。它在以下场景我实测下来效果很好Windows原生窗口、游戏客户端、自绘界面、嵌入WebView的混合应用。需要做跨端回归的情况同一套图像定位逻辑可以从Windows切到Android脚本改动很小。界面经常变但视觉特征稳定的产品光是微调图片素材就能继续跑。不太适合的场景也有需要大量后端接口断言、需要高频读取表格数据进行复杂计算、对测试运行时间要求极苛刻的任务。图像识别本身有毫秒级的截图和匹配开销把它当成纯单元测试工具用方向就错了。2. 动手前的环境判断与版本选型很多人安装Airtest失败不是因为软件本身问题而是环境没有提前处理好。我自己在Windows上装过纯命令行环境和AirtestIDE两条路线下面把环境准备的关键点整理清楚。2.1 Windows版本、Python版本与显示缩放的影响Airtest对Windows版本的要求不算苛刻我在Windows 10和Windows 11上都跑通过。需要注意的倒是Python版本选择。官方文档长期声明支持Python 3.6到3.9后来版本对3.10、3.11兼容性也在改善。我实测下来Python 3.10环境装airtest和pocoui很顺畅Python 3.12上则可能遇到个别依赖包没有预编译版本的情况所以保守一点建议直接用Python 3.10。显示缩放是我这一路遇到的最大坑。Windows系统默认把显示缩放设为125%或150%时Airtest截图和点击的坐标会产生偏差截图看起来是正常的但点击位置会往右下角偏。后面踩坑章节我会详细说解决方案环境准备阶段就要有意识要么把跑测试机器的显示缩放固定为100%要么所有脚本素材都在同一个缩放比例下截图。另外如果你的测试对象是Windows桌面应用尽量让被测窗口保持固定的启动大小和位置不要让它最大化或移动到副屏。窗口位置变化虽然图像识别能扛住但部分极端情况会因遮挡导致匹配失败。2.2 两条路线AirtestIDE与纯pip脚本Airtest提供两种使用方式新手和自动化老手的选择差异很大。对比项AirtestIDE纯pip命令行安装方式下载压缩包解压即用pip install airtest自带Python环境自带独立依赖系统Python/虚拟环境图形化录制支持适合新手不支持运行与报告界面一键运行/打开报告命令行运行/生成报告适合场景脚本开发、调试、演示CI集成、批量执行、正式回归我个人的建议是IDE和pip环境都要装。IDE负责开发脚本、截图素材、单步调试pip环境负责跑批量回归和对接持续集成。两条路线共用同一个脚本目录互不冲突。AirtestIDE本质上是一个打包好的开发环境它会带一份独立的Python所以即使你系统Python装坏了IDE里的脚本依然能跑。但如果要把脚本交给CI服务器执行就得靠pip环境。2.3 安卓模拟器与真机的前置准备如果你除了Windows桌面应用还想顺手验证移动端场景那需要先准备好ADB环境。Airtest连接Android设备时依赖ADB来做设备通信。真机需要开启开发者模式并打开USB调试模拟器则有各自的调试端口。常见Android模拟器端口并不统一夜神模拟器常见的是62001雷电模拟器常见的是5555或5554逍遥模拟器常见的是21503MuMu模拟器有7555和16316等。需要注意的是这些端口会因为模拟器版本不同而变化最准确的办法是在模拟器设置里找到ADB调试端口或者直接运行adb devices查看当前识别到的设备编号。如果你暂时只做Windows桌面应用这节可以跳过。但安装完AirtestIDE后它自带的ADB会自动启动连接移动设备时基本不用额外配置。3. 完整安装过程IDE和命令行双路线实测安装过程看起来简单但实际执行时有不少细节。我把两种路线从头到尾走了一遍记录下每个关键步骤和可能出现的问题。3.1 安装AirtestIDE第一步是去Airtest官网下载AirtestIDE。下载完成后得到的是一个压缩包解压到本地目录进入目录后双击AirtestIDE.exe即可启动不需要执行安装程序。这里有一个非常重要的实测经验解压路径不要带中文也不要有空格。刚开始我把IDE放到D:\自动化工具\AirtestIDE启动时部分功能异常ADB初始化失败改成D:\Tools\AirtestIDE之后一切正常。启动IDE后界面左侧是设备连接区右侧是脚本编辑区和截图区。首次启动会自动检出当前接入的Android设备同时会尝试初始化ADB。如果杀毒软件弹窗拦截需要允许程序运行否则设备连接和截图功能会直接失效。AirtestIDE自带Python运行环境和全部依赖所以你打开IDE就能新建.air脚本并直接运行。这也是为什么我建议新手先装IDE它帮你屏蔽掉了环境变量、依赖版本这些乱七八糟的事情。3.2 用pip安装独立运行环境如果要在命令行环境里跑脚本或者要让脚本可以在CI上执行建议单独建一个虚拟环境来安装Airtest。我常用的命令如下python -m venv .venv .venv\Scripts\activate pip install --upgrade pip setuptools wheel pip install airtest pocoui这里安装两个包airtest是核心自动化框架负责截图、点击、查找图像pocoui是Poco SDK用于控件树定位。如果你只需要纯图像识别不打算用Poco只装airtest也足够。安装完成后可以用以下命令验证python -c import airtest; print(airtest.__version__)我在Windows上实测输出类似1.3.0的版本号。如果pip下载速度很慢可以临时指定国内镜像源pip install airtest pocoui -i https://pypi.tuna.tsinghua.edu.cn/simple3.3 首次启动验证环境装好后不要急着写复杂用例先做一个最小验证连接Windows设备并截一张图。在AirtestIDE里设备连接区下拉选择Windows点击连接界面会刷新一张桌面截图。这说明Airtest已经能访问当前Windows会话画面。命令行环境下可以写一个最简单的脚本from airtest.core.api import * auto_setup(__file__, logdirTrue, devices[Windows:///]) snapshot(first_snapshot.png)运行后脚本会截取当前Windows桌面并保存图片。如果这一步能成功说明截屏、设备连接、日志目录都正常可以进入正式的脚本编写阶段。3.4 安装失败的常见处理我实际踩过的安装失败主要有三种。第一pip install过程中报编译错误。这类问题多半是某个依赖包需要本地编译而系统缺少C构建工具。解决办法是提前装好Microsoft C Build Tools或者换用Python 3.10版本避开部分预编译缺失的坑。第二提示No module named airtest。看到这个报错先别慌大概率是当前命令行激活的Python环境和你安装包时用的Python环境不一致。在Windows上执行where python看一下当前用的是哪个解释器确认它和你pip install时用的是同一个。第三IDE启动后ADB一直转圈。可以检查IDE解压路径是否含中文也可以手动在设置里把ADB路径指向你系统里已有的ADB工具。多数情况是杀毒软件把IDE内部的ADB进程拦了放行之后就好了。4. 第一个脚本用Airtest跑通Windows窗口上的应用安装验证通过后接下来就是核心环节让Airtest在Windows窗口应用上完成一次真实的点击流程。这里我用Windows自带的记事本来演示思路也适用于任何桌面应用。4.1 连接Windows设备的两种方式在IDE里连接Windows设备只需要在设备类型里选择Windows即可这个方式适合开发调试时使用。命令行脚本里则需要通过设备URI来指定连接目标。from airtest.core.api import * connect_device(Windows:///)这段代码表示连接当前Windows桌面。Airtest会捕获当前整个桌面画面的截图所有图像识别都在这个画面范围内查找。如果同一时间打开了多个窗口需要注意目标窗口最好在最前面不要被其他窗口挡住。想要更精确地控制到某个固定窗口可以在脚本里用系统命令启动应用后先进行窗口前置操作再做后续点击。4.2 图像识别核心APItouch、wait、exists、assert_existsAirtest最常用的是下面这几个API都是围绕Template图片对象工作的。API作用关键参数touch点击找到的目标v、times、durationwait等待目标出现v、timeout、intervalexists判断目标是否存在vassert_exists断言目标必须存在v、msgassert_not_exists断言目标必须不存在v、msgTemplate是图像模板的构造器核心参数有三个threshold图像匹配阈值默认0.6表示相似度至少达到60%才认为匹配成功。阈值越高匹配越严格误报越少但也更容易漏匹配。target_pos点击位置相对于匹配区域的偏移位置取值范围1到9对应九宫格。默认是5也就是中心点。如果按钮中间有点击无效区域可以改成1到9中的其他位置。rgb是否开启彩色匹配。默认为False只比对亮度结构如果按钮颜色很重要可以开启rgbTrue。一个典型写法是这样的touch(Template(rbtn_open.png, threshold0.8, target_pos5))这个写法表示在屏幕上找到btn_open.png这张图相似度达到80%后点击它的中心点。4.3 用IDE录制时的注意事项AirtestIDE提供录制功能你连接Windows设备后点击录制然后像操作真实应用一样点击按钮IDE会把每一步操作转化为脚本。录制功能对快速上手很有帮助但直接生成的脚本有很明显的短板它默认记录的是坐标点击而不是图像识别点击。比如录制后你会看到touch((860, 540))这种脚本在窗口位置一变就会失效。正确做法是把坐标点击替换成图像识别touch(Template(rbtn_ok.png, threshold0.8))替换时注意所有图片素材都需要先用截图工具裁剪保存。在AirtestIDE里可以直接框选区域保存模板图片非常方便。我的习惯是先手动跑一遍应用流程把每个要操作的元素都截一遍图再组织脚本。4.4 跑脚本与查看报告IDE里直接点击运行按钮即可。命令行环境下需要先进入脚本目录然后执行python -m airtest run calc.air --device Windows:/// --log calc_log这里的calc.air不是单个文件而是一个目录。Airtest约定的.air项目目录里包含一个__init__.py脚本和若干图片素材。运行结束后生成日志目录再执行报告生成命令python -m airtest report calc.air --log_root calc_log --outfile calc_report.html打开生成的HTML报告可以看到每一步操作的前后截图、识别结果和断言结果。这个报告我在实际项目里直接发给开发和测试团队比贴一堆日志高效得多。5. 一个完整实测用例Windows计算器自动计算光讲理论不够我拿Windows系统自带的计算器设计了一个完整用例自动点击数字1、加号、数字2、等号最后断言结果区显示3。这个用例逻辑简单但覆盖了启动应用、图像定位、点击、断言、报告生成五个环节。5.1 用例需求与设计计算器界面上的数字键和运算符键在外观上相对稳定适合作为图像识别示例。用例流程如下启动calc.exe等待窗口出现。点击数字键1。点击加号键。点击数字键2。点击等号键。断言结果区域显示数字3。在开始写脚本前我需要先把这些键的图片截下来放到脚本目录里。素材文件建议用英文命名btn_1.png、btn_2.png、btn_plus.png、btn_equal.png、result_3.png。这样脚本可读性更强也避免中文路径在部分环境下引发编码问题。5.2 编写计算器脚本脚本内容如下import subprocess import time from airtest.core.api import * auto_setup(__file__, logdirTrue, devices[Windows:///]) subprocess.Popen(calc.exe) time.sleep(2.5) touch(Template(rbtn_1.png, threshold0.8)) touch(Template(rbtn_plus.png, threshold0.8)) touch(Template(rbtn_2.png, threshold0.8)) touch(Template(rbtn_equal.png, threshold0.8)) assert_exists(Template(rresult_3.png, threshold0.8), 12的结果应该显示为3)这里有几个细节需要说明。threshold0.8是我在计算器用例里实测比较合适的值比默认0.6严格不容易误点相邻按键。图片素材截取时建议只截取按键本体不要带周围大片背景否则背景变化会干扰匹配。time.sleep(2.5)是为了等计算器启动完成如果你的机器较慢可以适当调大。运行结束后如果断言失败报告里会标红错误步骤并显示实际截图你可以直接看出是没找到图片还是找错了位置。5.3 识别失败时怎么调计算器脚本看起来简单但我在实测定中仍然遇到几次识别失败的情况。最典型的是结果区域的3没有匹配上原因是计算器在不同系统主题下结果数字的颜色、粗细会有差异。遇到这种问题我通常按下面顺序排查重新截图当前实际运行的结果区域替换旧素材。调整threshold如果图片截得足够准确可以降到0.7如果图片截得不够准反而要升到0.85以上。开启rgbTrue用颜色辅助匹配避免相近形状的数字误匹配。用wait替代直接touch给页面加载留出时间避免元素还没出现就去点击。排查完之后我会在报告中对比前后两轮截图确认新素材的匹配位置确实是目标按钮。5.4 批量执行多个Windows用例计算器只是一个示例实际回归时不可能只跑一个用例。我的做法是把每个业务流程建立为一个独立的.air项目目录然后写一个Python脚本循环执行它们。python -m airtest run login.air --device Windows:/// --log logs/login_log python -m airtest run task.air --device Windows:/// --log logs/task_log python -m airtest run settings.air --device Windows:/// --log logs/settings_log每条命令执行完用airtest report生成各自报告。如果用例之间有先后关系就把它们按顺序串起来如果没有依赖也可以并行跑但并行时要注意设备冲突同一台Windows机器不建议多个Airtest进程同时截图。6. 真实踩坑记录从识别失败到设备断连工具装上、脚本能跑只是第一步真正让Airtest在Windows上稳定的是我连续踩了一周坑总结出来的一堆排查经验。下面这些问题是论坛和文档里不太会详细写的。6.1 ADB连不上安卓设备虽然这篇文章主场景是Windows但很多人会在同一台机器上同时做Android和Windows测试ADB问题很常见。现象是AirtestIDE里一直显示设备连接中或者脚本报错找不到设备。排查步骤我建议按顺序来adb devices如果列表里没有你的设备先检查模拟器的ADB调试开关或者真机的USB调试授权弹窗是否点了允许。如果列表显示offline执行adb kill-server adb start-server这能解决大部分ADB假死问题。还有一部分情况是模拟器多开导致端口冲突那就关闭多余模拟器或者手动指定模拟器端口。6.2 多显示器与DPI缩放导致点击偏移这是我在Windows环境遇到的最隐蔽的坑。一台带副屏的测试机器主屏缩放是125%副屏缩放是100%。Airtest在屏幕上截图看起来一切正常但点击时就是点到按钮右下角坐标明显偏移。根因是Windows的DPI缩放机制导致逻辑坐标和物理坐标不一致。Airtest截图时基于物理像素而点击事件在某些版本上按逻辑像素换算于是出现了偏差。解决办法有几种把测试机显示缩放统一设置为100%这是最省事的方案。如果项目必须用缩放那就保证脚本里所有图片素材都在目标缩放比例下截图且不要跨不同缩放的屏幕运行。多显示器环境只在主屏跑测试避免窗口落到副屏。这个坑对我的项目影响很大最后专门把CI测试机设置成固定分辨率、固定缩放100%才彻底解决。6.3 图片识别率突然下降有时候脚本昨天还全绿今天就跑挂了报错信息是找不到某个模板图片。我遇到的真实原因有几个Windows更新改变了系统深色/浅色模式计算器和设置界面整体配色变化另一个应用弹窗恰好遮挡了目标区域还有窗口大小被用户拖动过导致按钮缩放变形。应对方法是在脚本关键步骤前增加wait等待让目标完全显示后再操作。同时统一测试机的系统主题关闭弹窗干扰。对于窗口大小问题可以在自动化前置步骤里通过快捷键或命令把窗口恢复成标准尺寸。6.4 脚本运行到一半卡死卡死和找不到元素不一样它是脚本在某个touch或wait上长时间不返回。大多数原因是目标图片一直没有出现而代码里没有给timeout或者默认超时被设成了无限长。我在写脚本时有一个强制要求所有wait调用必须显式传timeout参数比如wait(Template(rbtn_submit.png), timeout20)同时给可能抛异常的步骤加上try...finally结构即使脚本失败也在finally里做清理动作比如截图留底、关闭被测应用。这样至少能保证失败现场有据可查。6.5 环境变量与包冲突这个坑主要出现在同时装了AirtestIDE和pip环境的机器上。AirtestIDE自带Python系统也装了Python命令行执行python和pip时用的可能是两个完全不同的环境。解决办法是在命令行里先激活虚拟环境再执行pip list确认airtest在这个环境里。运行脚本时也显式使用虚拟环境里的python -m airtest run不要直接敲airtest run。这看起来是小问题但能省掉非常多定位时间。7. 让Airtest脚本更可靠我的几个实操建议最后这部分不是官方文档里的基础用法而是我在真实项目里慢慢养成的习惯。按这套习惯写脚本维护成本会低很多。7.1 图像素材管理素材是Airtest项目最容易失控的地方。我的管理规范是这样素材统一放在对应.air目录下不用绝对路径引用统一用相对路径。命名规则用模块_元素_状态的格式比如task_btn_create.png、login_input_user.png。素材只截取元素本体尽量小但不要小到丢失特征。一个完整按钮是一张图不要为了省事截整个窗口。这样维护下来界面上一个按钮变了只需要替换对应图片脚本逻辑不动。7.2 合理设置超时与重试直接使用touch(Template(...))虽然方便但如果目标还没出现会直接失败。我更推荐先写一个通用的点击函数def click_tpl(tpl_path, timeout30): el wait(Template(tpl_path), timeouttimeout) touch(el)这样每次点击前都会等待元素出现超时时间也能统一控制。对于网络请求较慢的界面这个函数能显著降低脚本脆性。7.3 优先用Poco控件树不要硬怼图像图像识别能解决大部分问题但遇到列表项、动态加载内容、多种字体颜色变化的场景纯图像匹配会很吃力。这时候我建议尝试Poco控件树。以Android设备为例Poco初始化如下from poco.drivers.android import AndroidPoco poco AndroidPoco() poco(text确定).click()Windows端是否能用Poco取决于你的目标应用类型。自绘UI和游戏引擎控件通常有对应Poco驱动原生Win32控件则不一定能拿到理想控件树。我的原则是能用控件树定位的优先用控件树控件树拿不到的再用图像识别兜底。两者结合脚本的可靠性会提升一个档次。7.4 CLI与CI集成如果你和我一样需要每天自动化回归把Airtest脚本放进CI是绕不开的一步。我建议项目里维护一个requirements.txt锁定依赖版本airtest1.3.0 pocoui1.0.85CI执行时按以下顺序拉取代码创建虚拟环境。安装依赖。执行airtest run运行用例。执行airtest report生成报告。把报告上传到文件服务或发送通知。这里有一个容易忽略的点CI机器上的Windows账号不能自动锁屏锁屏状态下Airtest无法截取桌面画面脚本会直接失败。我给CI机器设置了长时间不锁屏才保证定时任务可以顺畅运行。7.5 日志与数据规范日志目录一定要规划好。auto_setup里设置logdirTrue之后每一次运行都会生成截图记录如果后续要对比历史结果最好在--log参数里带上时间戳目录。测试数据方面不要把敏感信息写死在脚本里。登录这类用例建议通过命令行参数或配置文件传入账号密码脚本里只读参数这样换环境跑的时候不用改脚本代码。最后再分享一个我自己的习惯每次改动素材图片后我都会先用IDE手动跑一遍单步调试确认点击位置在目标元素上再交付给CI执行。图像识别类自动化最怕的就是素材和脚本脱节把素材验收这一步前置能省掉很多后期排查成本。