☰
Airtest Windows桌面自动化测试实战指南
2026/9/30 4:29:38 网站建设 项目流程

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,逍遥模拟器常见的是21503,MuMu模拟器有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/simple

3.3 首次启动验证

环境装好后不要急着写复杂用例,先做一个最小验证:连接Windows设备并截一张图。

在AirtestIDE里,设备连接区下拉选择"Windows",点击连接,界面会刷新一张桌面截图。这说明Airtest已经能访问当前Windows会话画面。

命令行环境下,可以写一个最简单的脚本:

from airtest.core.api import * auto_setup(__file__, logdir=True, 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 图像识别核心API:touch、wait、exists、assert_exists

Airtest最常用的是下面这几个API,都是围绕Template图片对象工作的。

API作用关键参数
touch点击找到的目标v、times、duration
wait等待目标出现v、timeout、interval
exists判断目标是否存在v
assert_exists断言目标必须存在v、msg
assert_not_exists断言目标必须不存在v、msg

Template是图像模板的构造器,核心参数有三个:

  • threshold:图像匹配阈值,默认0.6,表示相似度至少达到60%才认为匹配成功。阈值越高,匹配越严格,误报越少,但也更容易漏匹配。
  • target_pos:点击位置相对于匹配区域的偏移位置,取值范围1到9,对应九宫格。默认是5,也就是中心点。如果按钮中间有点击无效区域,可以改成1到9中的其他位置。
  • rgb:是否开启彩色匹配。默认为False,只比对亮度结构;如果按钮颜色很重要,可以开启rgb=True。

一个典型写法是这样的:

touch(Template(r"btn_open.png", threshold=0.8, target_pos=5))

这个写法表示:在屏幕上找到btn_open.png这张图,相似度达到80%后,点击它的中心点。

4.3 用IDE录制时的注意事项

AirtestIDE提供录制功能,你连接Windows设备后点击录制,然后像操作真实应用一样点击按钮,IDE会把每一步操作转化为脚本。录制功能对快速上手很有帮助,但直接生成的脚本有很明显的短板:它默认记录的是坐标点击,而不是图像识别点击。

比如录制后你会看到:

touch((860, 540))

这种脚本在窗口位置一变就会失效。正确做法是把坐标点击替换成图像识别:

touch(Template(r"btn_ok.png", threshold=0.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 用例需求与设计

计算器界面上的数字键和运算符键在外观上相对稳定,适合作为图像识别示例。用例流程如下:

  1. 启动calc.exe,等待窗口出现。
  2. 点击数字键1。
  3. 点击加号键。
  4. 点击数字键2。
  5. 点击等号键。
  6. 断言结果区域显示数字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__, logdir=True, devices=["Windows:///"]) subprocess.Popen("calc.exe") time.sleep(2.5) touch(Template(r"btn_1.png", threshold=0.8)) touch(Template(r"btn_plus.png", threshold=0.8)) touch(Template(r"btn_2.png", threshold=0.8)) touch(Template(r"btn_equal.png", threshold=0.8)) assert_exists(Template(r"result_3.png", threshold=0.8), "1+2的结果应该显示为3")

这里有几个细节需要说明。threshold=0.8是我在计算器用例里实测比较合适的值,比默认0.6严格,不容易误点相邻按键。图片素材截取时,建议只截取按键本体,不要带周围大片背景,否则背景变化会干扰匹配。time.sleep(2.5)是为了等计算器启动完成,如果你的机器较慢,可以适当调大。

运行结束后,如果断言失败,报告里会标红错误步骤,并显示实际截图,你可以直接看出是没找到图片还是找错了位置。

5.3 识别失败时怎么调

计算器脚本看起来简单,但我在实测定中仍然遇到几次识别失败的情况。最典型的是结果区域的3没有匹配上,原因是计算器在不同系统主题下,结果数字的颜色、粗细会有差异。

遇到这种问题,我通常按下面顺序排查:

  • 重新截图当前实际运行的结果区域,替换旧素材。
  • 调整threshold,如果图片截得足够准确,可以降到0.7;如果图片截得不够准,反而要升到0.85以上。
  • 开启rgb=True,用颜色辅助匹配,避免相近形状的数字误匹配。
  • 用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(r"btn_submit.png"), timeout=20)

同时给可能抛异常的步骤加上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, timeout=30): el = wait(Template(tpl_path), timeout=timeout) 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,锁定依赖版本:

airtest==1.3.0 pocoui==1.0.85

CI执行时按以下顺序:

  1. 拉取代码,创建虚拟环境。
  2. 安装依赖。
  3. 执行airtest run运行用例。
  4. 执行airtest report生成报告。
  5. 把报告上传到文件服务或发送通知。

这里有一个容易忽略的点:CI机器上的Windows账号不能自动锁屏,锁屏状态下Airtest无法截取桌面画面,脚本会直接失败。我给CI机器设置了长时间不锁屏,才保证定时任务可以顺畅运行。

7.5 日志与数据规范

日志目录一定要规划好。auto_setup里设置logdir=True之后,每一次运行都会生成截图记录;如果后续要对比历史结果,最好在--log参数里带上时间戳目录。

测试数据方面,不要把敏感信息写死在脚本里。登录这类用例,建议通过命令行参数或配置文件传入账号密码,脚本里只读参数,这样换环境跑的时候不用改脚本代码。

最后再分享一个我自己的习惯:每次改动素材图片后,我都会先用IDE手动跑一遍单步调试,确认点击位置在目标元素上,再交付给CI执行。图像识别类自动化最怕的就是素材和脚本脱节,把素材验收这一步前置,能省掉很多后期排查成本。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询