AI自动化测试框架对比:Airtest与Open-AutoGLM的选型与落地实践
1. 项目概述当AI测试框架相遇我们到底在谈什么最近在AI自动化测试的圈子里Open-AutoGLM和Airtest这两个名字被提及的频率越来越高。很多刚入行的朋友甚至一些有经验的测试工程师都跑来问我“这俩到底有啥区别我该用哪个听说坑不少怎么避” 作为一个在自动化测试领域摸爬滚打了十多年的老兵我亲眼见证了从脚本录制回放到基于图像识别的Airtest再到如今引入大语言模型的Open-AutoGLM每一次技术迭代都伴随着巨大的期望和同样巨大的困惑。今天我就从一个一线实践者的角度抛开那些天花乱坠的宣传词跟你掰扯掰扯这两个框架的底层机制到底有什么不同更重要的是在实际项目落地时那些文档里不会写的“坑”在哪里以及我们该怎么绕过去。简单来说Airtest更像是一位经验丰富的“图像识别专家”它通过“看”屏幕上的像素点来定位和操作元素而Open-AutoGLM则像是一位新来的“语义理解实习生”它尝试去“理解”界面元素的含义和关系然后用自然语言指挥操作。听起来后者更智能、更未来对吧但现实往往比理想骨感。选择哪一个绝不单单是技术先进性的问题更是对项目需求、团队技能、维护成本和稳定性的综合考量。这篇文章我会带你深入到它们的引擎盖下面看看并结合我趟过的雷、填过的坑给你一份实实在在的落地指南。2. 底层机制深度拆解从“看见”到“理解”的鸿沟要理解两者的差异必须从最根本的“如何定位一个按钮”说起。这个看似简单的动作背后是两套截然不同的哲学和技术栈。2.1 Airtest基于图像与控件树的“确定性”世界Airtest的核心机制可以概括为“双轨制”图像识别为主辅以原生控件树访问。这是它稳定性的基石。图像识别核心这是Airtest的看家本领。它并不是简单地进行全图匹配。当你对某个UI元素比如一个登录按钮截图作为模板时Airtest会提取该图像的特征点。在运行时它会在当前设备屏幕上进行特征点匹配通常使用如AKAZE、BRISK等算法。匹配成功后会返回一个置信度得分和匹配区域的坐标。你写的touch(Template(“login_button.png”))背后就是这套流程。它的优势在于“所见即所得”不关心你这个按钮是Android的Button还是iOS的UIButton或是Web里的div只要样子一样就能操作。这对于游戏、跨平台应用或无法直接获取控件树的场景是救星。原生控件树访问辅助对于Android和iOS应用Airtest通过ADB或WebDriverAgent等通道可以获取到当前界面的UI控件层级结构类似于Android的UIAutomator或iOS的XCUITest看到的。你可以使用poco(“确定”)这样的方式通过控件的文本、类型等属性进行定位。这为基于属性的精准定位提供了可能。注意Airtest的图像识别严重依赖屏幕分辨率、缩放比例、颜色和光照环境。同一个应用在不同型号手机、不同系统主题下截图模板可能需要准备多套。而控件树访问则要求应用本身对无障碍功能或UI测试框架有较好的支持否则可能无法获取到控件信息。它的“确定性”就体现在这里要么匹配到图像达到设定的阈值要么在控件树里找到对应属性的节点然后执行坐标点击或控件操作。整个过程是相对静态和可预测的。2.2 Open-AutoGLM基于大模型的“语义化”推理Open-AutoGLM代表了一种新范式。它的核心不是“匹配”而是“理解”和“规划”。其底层机制可以分解为几个关键步骤屏幕理解与元素标注首先它通过ADB或其他方式捕获当前屏幕截图。然后这张截图被送入一个多模态大模型例如GLM系列或类似的视觉-语言模型。模型的任务不是进行像素级匹配而是“看懂”屏幕识别出哪些区域是按钮、输入框、文本标签并推断出它们的可能功能如“这是一个用于提交的按钮”、“这是一个输入用户名的文本框”。同时模型会为这些识别出的元素生成描述性标签或ID。自然语言指令解析你写的测试用例可能是这样的自然语言“在搜索框输入‘自动化测试’然后点击搜索按钮”。Open-AutoGLM会利用大语言模型LLM解析这条指令将其分解成一系列原子操作意图定位“搜索框” - 执行“输入”操作内容为“自动化测试” - 定位“搜索按钮” - 执行“点击”操作。意图与元素的关联这是最关键也最易出错的一步。系统需要将“搜索框”这个意图与屏幕理解阶段标注出来的某个具体元素比如一个被标注为“可能是一个搜索输入框”的区域关联起来。这种关联依赖于模型对语义的理解能力。例如它需要知道“搜索框”通常是一个矩形框旁边可能有放大镜图标或者里面有“请输入关键词”的提示文本。操作执行与状态验证关联成功后框架会通过底层自动化引擎可能是ADB命令也可能是其他驱动执行点击、输入等操作。之后可能会再次截图让模型判断操作结果是否符合预期如“是否出现了搜索结果列表”。与Airtest的根本差异Airtest需要你明确告诉它“点哪里”通过图片或属性。Open-AutoGLM则是你告诉它“做什么”它自己去找“哪里”点。后者更接近人类测试的思维模式但引入了“模型理解是否准确”这个巨大的不确定性。这个不确定性就是大多数“坑”的来源。3. 核心差异对比与选型决策矩阵理解了底层机制我们可以从几个维度进行系统性的对比这直接决定了你的技术选型。对比维度AirtestOpen-AutoGLM选型启示定位原理图像特征匹配 / 控件属性匹配多模态大模型语义理解求稳选Airtest求新选Open-AutoGLM。对稳定性要求极高的线上回归测试Airtest更可靠。脚本编写基于坐标/图片/控件属性的显式编程。需要录制或手动编写。基于自然语言的描述。可自动生成或手动编写意图。团队技能Airtest需要测试有编程基础。Open-AutoGLM降低了编码门槛但对测试用例的描述能力要求高。维护成本高。UI改动后需要更新截图模板或控件定位语句。潜在较低。模型有一定泛化能力小幅UI调整如颜色变化、轻微位移可能不影响执行。但逻辑大变仍需调整描述。UI稳定性产品UI迭代频繁且改动大时两者维护成本都高。Open-AutoGLM对纯样式改动容忍度稍高。执行速度较快。图像匹配和控件查找是计算密集型但流程直接。较慢。涉及多次模型推理截图理解、指令解析耗时远超传统方法。对执行时效有严格要求如CI/CD快速反馈的场景Airtest优势明显。跨平台能力强。图像识别无视平台控件树支持主流移动端和Windows。依赖模型能力。理论上可跨任何有屏幕的设备但实际效果取决于模型对特定平台UI模式的训练程度。测试游戏、嵌入式设备UI等非常规平台Airtest更成熟。稳定性较高。在环境一致分辨率、主题的情况下结果可重复。较低。模型推理存在随机性相同指令在不同时间执行可能关联到不同元素或产生不同理解。关键业务路径的自动化目前不建议完全依赖Open-AutoGLM可作为补充或探索性测试工具。初始投入较低。框架成熟资料多容易上手。较高。需要理解大模型概念可能涉及本地模型部署成本高或调用API有费用和网络依赖。评估团队的技术储备和预算。选型决策的心得不要被“AI”、“智能”这些词迷惑。我目前的策略是“混合使用各取所长”。对于核心的、稳定的业务流程如登录、支付使用Airtest编写健壮的脚本保证回归测试的稳定性。对于探索性测试、快速覆盖大量简单场景、或者UI经常微调的非核心页面可以尝试用Open-AutoGLM来快速生成测试脚本提升覆盖率。Open-AutoGLM更像是一个强大的“测试脚本生成助手”和“探索性测试执行器”而非完全替代传统自动化框架。4. Open-AutoGLM落地实操与关键配置如果你决定尝试Open-AutoGLM那么接下来的实操细节将至关重要。以下基于开源项目和一些实践梳理出关键步骤。4.1 环境搭建与模型选型首先你需要一个“大脑”即多模态大模型。你有两个选择调用云端API如OpenAI GPT-4V Google Gemini Pro Vision最简单快捷无需本地硬件资源。但存在持续成本、网络延迟、数据隐私截图可能上传和API调用频率限制等问题。对于企业级应用数据安全是首要考量。部署本地模型如Qwen-VL InternLM-XComposer数据完全私有可控性强。但对GPU显存要求高通常需要8G以上且模型效果可能略逊于顶级云端API。这是目前很多企业PoC概念验证的方向。实操步骤建议从云端API开始验证先用GPT-4V等成熟API快速验证想法跑通整个流程。编写一个简单的Python脚本将截图Base64编码后发送给API请求其描述屏幕元素。本地部署做PoC如果验证可行考虑在本地部署一个中等规模的模型。Docker是目前最友好的方式。例如使用官方提供的Docker镜像运行Qwen-VL-Chat模型。# 假设有现成的Docker镜像 docker pull qwenvl/qwen-vl-chat:latest docker run -it --gpus all -p 8080:8080 qwenvl/qwen-vl-chat随后你的测试代码将通过HTTP请求与本地模型的API端点交互。关键配置参数与模型交互时Prompt提示词是成败的关键。你提供给模型的指令必须清晰、无歧义。# 一个糟糕的Prompt示例 prompt “描述这张图片。” # 一个好的Prompt示例结构化明确任务 prompt “”” 你是一个UI界面分析专家。请分析这张应用截图 1. 找出所有可交互的元素如按钮、输入框、链接、选项卡。 2. 为每个元素分配一个唯一的ID如btn_1, input_1。 3. 描述每个元素的外观特征和可能的功能用一句话说明。 4. 以JSON格式输出格式如下{elements: [{id: btn_1, type: button, description: 一个蓝色的、带有‘登录’文字的矩形按钮, function: 用于提交用户名和密码以登录系统}]} “””清晰的Prompt能极大提升模型输出的结构化程度和可用性。4.2 测试用例设计与编写艺术在Open-AutoGLM中编写测试用例不是写代码而是写“任务说明书”。传统 vs AI自动化测试用例对比Airtest风格# 显式定位和操作 touch(Template(login_button.png)) # 点击登录按钮图片 text(“username_input.png”, “my_username”) # 在用户名输入框图片处输入文本Open-AutoGLM风格# 或自然语言描述 test_case: name: “用户登录流程” steps: - action: “输入” target: “用户名输入框” data: “test_userexample.com” - action: “输入” target: “密码输入框” data: “MyPassword123” - action: “点击” target: “登录按钮” validation: - “检查是否成功跳转到主页” - “检查页面顶部是否显示用户名‘test_user’”甚至可以直接是一段话“请执行用户登录操作用户名是test_userexample.com密码是MyPassword123然后验证是否登录成功进入首页。”设计心得原子化将一个复杂流程拆解成原子操作点击、输入、滑动、验证。每个原子操作的成功率更高。描述精准化避免使用“那个按钮”、“左边的框”这种模糊指代。使用界面上的唯一文本、功能名称或相对位置如“搜索栏下方的第一个商品卡片”进行描述。引入验证点每一步操作后都应设计明确的验证点。Open-AutoGLM可以截图后让模型判断验证点是否通过例如“请判断当前页面是否包含‘登录成功’的提示文字”。5. Airtest实战避坑指南与性能优化Airtest虽然成熟但坑一点不少。下面是我用“血泪”换来的一些核心经验。5.1 图像识别稳定性提升技巧图像识别是Airtest的命门也是最大的不稳定源。模板图片制作规范尺寸适中截取的元素图片不要太大包含过多无关背景或太小特征点不足。只包含目标元素及其少量周边上下文为宜。关注不变特征截取时尽量选择UI中不会变化的部分。例如一个按钮截取它的图标和文字部分避免截取带有动态阴影或光效的边缘。多分辨率适配如果你的应用要覆盖多种手机必须为关键UI元素准备多套模板对应不同的分辨率如1080p, 1440p。可以使用Airtest提供的auto_setup接口根据当前设备分辨率自动选择模板集。touch与wait的黄金组合 不要直接touch而是先wait。wait函数会返回匹配到的坐标并且你可以设置等待时间和阈值。# 不推荐的写法 touch(Template(“submit.png”)) # 推荐的写法 try: pos wait(Template(“submit.png”, threshold0.8, timeout10)) # 等待10秒匹配阈值0.8 if pos: touch(pos) # 使用wait返回的坐标进行点击更精准 else: raise Exception(“未找到提交按钮”) except TargetNotFoundError: # 执行备用方案比如记录日志、尝试其他定位方式 log(“提交按钮未找到尝试通过控件树定位...”) poco(“提交”).click()threshold阈值是关键参数默认0.7可能不够。对于清晰、不变的元素可以调到0.9对于有轻微形变或颜色变化的可能0.75更合适需要反复调试。启用RGB识别默认情况下Airtest的图像识别会先将图片转成灰度图这可能会丢失颜色特征。对于依赖颜色区分的UI比如不同状态的指示灯可以启用RGB识别但计算量会增大。touch(Template(“red_button.png”, rgbTrue))5.2 控件树Poco定位最佳实践当图像识别搞不定时或者追求更高执行效率时Poco是更好的选择。选择稳定的定位属性绝对避免使用indexpoco(“XXX”)[0]这种写法极度脆弱UI顺序一变就挂。优先使用text、name或type这些通常是开发赋予控件的语义化属性相对稳定。使用attr进行模糊匹配poco(textMatches“.*登录.*”)可以匹配包含“登录”二字的控件。组合使用poco(type“Button”, text“确定”)比单用text更精准。应对动态ID和内容 很多现代框架如React Native, Flutter会生成随机的控件ID。此时需要通过相对定位或父子层级关系来定位。# 假设一个列表项结构不稳定但内部有一个稳定的文本元素 # 错误直接定位列表项本身 # poco(“android.widget.ListView”).child(“android.widget.LinearLayout”)[0].click() # 正确先定位稳定的子元素再找其父级或兄弟元素 target_text poco(text“稳定的商品名称”) # 方法1点击这个文本元素本身如果可点 target_text.click() # 方法2通过父级定位操作兄弟元素比如旁边的“购买”按钮 buy_button target_text.parent().child(type“Button”, text“购买”) buy_button.click()focus和scroll的运用对于不在屏幕内的元素需要先滚动使其可见。Poco提供了scroll方法可以指定方向直到找到目标元素。# 在列表中找到目标项并滚动到视野内 list_view poco(“android.widget.ListView”) target_item list_view.child(text“目标项”) target_item.scroll_to_view() # 滚动直到该项可见 target_item.click()6. 混合框架实践让AI与传统自动化协同工作我认为最务实的路线不是二选一而是让它们协同。这里分享一个我们正在使用的混合框架设计思路。架构设计用例管理层用YAML或JSON管理测试用例。一个用例包含“自然语言描述”和“传统脚本”两种实现方式或仅有一种。调度与执行引擎解析器读取用例判断其类型。AI执行器对于标记为“AI”或自然语言的用例调用Open-AutoGLM服务将描述转化为具体的操作指令序列可缓存结果避免每次执行都调用模型。传统执行器对于标记为“传统”或已有脚本的用例直接调用Airtest或Poco引擎执行。融合器高级对于复杂用例可以用AI生成操作步骤的“草稿”然后由传统执行器去优化和落实具体的定位语句例如AI识别出“点击登录按钮”融合器将其转化为poco(text“登录”).click()。结果分析与自愈AI辅助断言对测试结果的验证可以引入AI模型来判断截图是否包含预期的成功状态这比写死的图像匹配更灵活。失败自愈当传统脚本因UI微调失败时可以触发AI模块尝试用自然语言描述原操作意图让AI在新的UI上重新定位并执行并将成功的新定位方式反馈给脚本库实现一定程度的自我修复。一个简单的协同示例 假设有一个“发布新帖子”的功能UI经常改版。首次实现用Airtest录制/编写一套稳定脚本。UI改版后脚本失败系统检测到失败触发AI流程。AI流程将原用例意图“发布新帖子”和当前屏幕截图传给模型模型规划出新步骤“点击右下角浮动按钮 - 点击‘文字’图标 - 在顶部输入框输入内容 - 点击‘发布’按钮”。执行与学习AI执行器尝试执行这些步骤。如果成功系统自动将这一系列新的定位逻辑可能是图像特征或控件属性记录下来更新或补充到该用例的“备用执行方案”中。下次执行优先尝试传统脚本如果失败自动切换到AI推导出的备用方案。这种方式既保留了传统自动化的执行效率又获得了AI的灵活性和适应性是目前看来最具可行性的落地路径。7. 常见问题排查与调试技巧实录无论用哪个框架调试都是必修课。下面是一些高频问题的排查思路。7.1 Open-AutoGLM专属问题问题1模型“看不懂”或“找错”元素。排查首先检查输入给模型的屏幕截图是否清晰、完整截图时机是否正确是否在页面稳定后其次分析Prompt指令是否模糊尝试将指令写得极其详细和结构化例如“请找到屏幕上唯一一个背景为蓝色、文字为白色且内容是‘立即购买’的矩形按钮”。技巧实现一个“调试模式”将模型对屏幕的理解结果标注了元素ID和描述的图片保存下来。直观地看模型把哪个区域当成了“登录按钮”能快速定位问题。备用方案在AI指令中可以加入“如果找不到A请尝试寻找B”的备用描述。或者当AI多次失败时自动降级到预置的关键坐标点击如果UI布局大体稳定。问题2执行顺序混乱或漏步骤。排查模型生成的步骤序列是否合理检查其输出是否被正确解析为有序的操作列表。有时模型会合并或拆分步骤。技巧在每一步操作执行前强制等待1-2秒并再次截图确认当前界面状态是否符合继续执行的条件。实现“状态检查点”。问题3执行速度慢无法用于大规模测试。排查瓶颈在模型推理速度。如果是云端API网络延迟是主因如果是本地模型GPU性能是主因。优化缓存对于不变的界面如App启动页其元素分析结果可以缓存下次直接使用。模型蒸馏使用更小、更快的专用模型替代通用大模型牺牲一点精度换取速度。异步执行将截图和分析任务异步化不阻塞测试主流程但会增加复杂度。7.2 Airtest通用问题问题1ImageNotFound或TargetNotFoundError。排查清单截图模板问题模板图片是否正确是否因手机主题、字体大小、分辨率不同而失效阈值问题当前屏幕截图与模板的匹配度是否低于设定的threshold尝试调低阈值如0.6但会增加误触风险。等待时间问题页面元素尚未加载出来就进行查找增加wait的timeout参数。屏幕状态问题是否有悬浮窗、通知栏下拉、屏幕亮度变化干扰了识别调试命令使用Airtest IDE的snapshot和assert_exists功能进行实时调试。在脚本里加入snapshot(msg“当前屏幕状态”)保存失败时的截图便于事后分析。问题2点击坐标不准确。排查wait返回的坐标本身就是错误的还是点击时发生了偏移Airtest的touch默认会点击匹配区域的中心点。解决使用wait返回的pos变量它是一个矩形区域(x, y, width, height)。可以尝试点击这个区域内的特定偏移点例如touch((pos[0]10, pos[1]10))点击中心偏右下的位置。对于不规则形状或需要精确点击的点如游戏技能图标可以使用TouchPos类或者直接使用poco的控件点击后者通常更精准。问题3在部分设备上运行缓慢。排查设备性能老旧手机CPU处理图像慢。截图频率脚本中是否频繁进行不必要的截图或图像识别网络延迟如果使用了Poco且应用是WebView或混合应用控件查找可能涉及网络通信。优化减少sleep的使用多用wait进行智能等待。对于不变的元素将其定位结果坐标或控件对象存入变量重复使用避免重复查找。考虑使用更高效的图像匹配算法设置在Airtest初始化时配置或在低性能设备上适当降低截图分辨率。自动化测试没有银弹无论是传统的Airtest还是新兴的Open-AutoGLM都是我们手中的工具。我的体会是在追求效率革新的同时永远不能放弃对稳定性和确定性的底线要求。将AI作为增强传统自动化的“副驾驶”而非完全替代驾驶员的“自动驾驶”在现阶段可能是最稳妥、最能产生实际价值的策略。先在小范围、非核心的场景中用起来积累经验和信心再逐步扩大其应用边界或许是我们应对这场技术变革最理性的方式。