☰
基于OpenClaw与Qwen3.5-9B的UI自动化测试用例生成与执行
2026/10/20 6:39:12 网站建设 项目流程

写UI自动化测试写了快十年,我其实有个一直没绕过去的坎:用例编写和维护的成本实在太高。页面一改,用例跟着碎一地。后来我开始折腾把大语言模型接进测试流程,让模型去生成用例、再去驱动执行。完整方案跑下来,就是这套基于OpenClaw自动化测试框架、由Qwen3.5-9B这个9B级开源模型承担UI测试用例生成与执行任务的项目。这篇文章里,我把整个设计思路、实现细节和踩坑经历都拆开讲,给正在犹豫要不要把模型引入测试环节的团队一个可落地的参考。无论你是测试开发、质量保障负责人,还是想转型AI测试的开发者,这套东西都能给你不少能直接抄作业的路径。

1. 先把需求聊明白:这套方案到底解决什么问题

1.1 传统UI用例维护,痛点比你想的多

我在多个业务系统上维护过UI自动化用例集,印象最深的一个中后台项目,用例总量超过了三千条。看起来规模不大,但每个迭代版本里,有将近三分之一的时间花在改用例上。页面导航变了、按钮文案换了、弹窗结构调整了,都会导致一串用例变红。最典型的场景是搜索页面加了一个筛选条件,DOM结构整体下移,所有依赖旧结构的定位表达式全部失效。这类问题不是测试框架能解决的,本质上是页面结构与用例之间的强耦合。

手工写用例还有一个隐性成本:风格不统一。A同学喜欢用XPath长路径定位,B同学习惯给元素加>你是一名资深UI自动化测试工程师。请根据给定的页面结构、业务需求和元素库,生成符合JSON Schema的UI测试用例。 ## 页面结构 {page_hierarchy} ## 业务需求 {user_story} ## 元素库 {element_registry} ## 约束条件 1. 只输出合法的JSON数组,不要包含任何解释性文字。 2. 每个操作步骤必须包含定位器,优先使用data-testid,其次使用id。 3. 断言必须包含可机器判定的条件,禁止模糊描述。 4. 涉及弹窗和iframe时,必须加入对应的切换步骤。 5. 步骤数量控制在20步以内,避免拆解过细。 ## 输出示例 {one_few_shot_example}

这个模板里有几个细节值得注意。约束条件必须放在输入素材之后、示例之前,因为模型对越靠后的指令遵循能力通常越强。少样本示例只需要一条,但这一条必须完整覆盖登录、查询、分页、断言、清理这样一个完整链路,让模型看到"完整用例"长什么样,而不是零散片段的堆砌。

温度参数我控制在0.2到0.4之间。温度太高,模型会在步骤描述里自由发挥,输出各种不存在的交互方式;温度太低,则会让步骤变得机械重复。0.3是我试下来稳定性和灵活性都兼顾的值。

3.3 用例Schema:让模型输出可以被执行器消费

如果让模型用自然语言自由写用例,执行层根本没法解析。所以必须定义一套用例Schema,要求模型输出严格遵守。这套Schema本质上是模型和执行引擎之间的契约,我把它叫做UI用例定义对象。

{ "case_id": "order_search_pagination_001", "title": "订单搜索功能翻页后数据正确显示", "preconditions": [ "用户已登录后台管理账号", "系统存在至少两页测试订单数据" ], "steps": [ {"action": "goto", "target": "/order/list", "desc": "进入订单列表页"}, {"action": "input", "target": "#search-keyword", "value": "2025", "desc": "输入订单号关键字"}, {"action": "click", "target": "#search-btn", "desc": "点击搜索按钮"}, {"action": "click", "target": ".pagination-next", "desc": "点击下一页"}, {"action": "wait", "condition": ".order-row:loaded", "desc": "等待下一页数据加载完成"} ], "assertions": [ {"type": "element_text", "target": ".page-info", "expected": "第2页/共10页", "operator": "contains"}, {"type": "element_count", "target": ".order-row", "expected": 20, "operator": "eql"} ], "data": {}, "cleanup": [{"action": "reset_search", "target": "#reset-btn", "desc": "重置搜索条件"}] }

这个Schema定义了四块核心内容。步骤列表是执行的主体,每一项包含动作类型、目标定位符、参数和自然语言描述;断言定义了判断用例通过与否的标准;清理步骤保证用例执行完不污染环境,这一点在重复执行时特别重要;前置条件用于执行器判断是否满足跳过或初始化要求。

设计Schema时,我有意把动作类型限制在一个小的枚举集合内,包括goto、input、click、wait、select、screenshot等常用操作。限制枚举范围能显著提高模型输出的规范性,避免它自创动作导致执行器无法映射。

4. 完整跑一遍:部署、接入、生成、执行

4.1 本地部署Qwen3.5-9B推理服务

部署部分没有什么黑魔法,跟着常规的大模型本地化流程走就行。我用的是一台带24G显存的GPU服务器,操作系统是CentOS兼容的发行版,Python环境用虚拟环境隔离。模型权重从仓库拉取Int8量化版本后,放进一个符合推理框架要求的目录结构里。

模型服务启动后,会在本地监听一个HTTP端口,对外暴露/v1/chat/completions接口。这个接口格式是当前大模型社区事实上的标准,OpenClaw的生成层可以直接按这个规范对接。我实际测试时,启动命令跑完之后等一分钟左右,接口就返回健康状态了。用curl发一个最小请求确认服务在线,再进入下一步配置。

注意:模型服务启动前,确认显卡驱动和推理框架版本是匹配的。我踩过一次驱动版本过低导致量化模型加载后推理速度骤降的坑,后来统一升级驱动才恢复正常。

4.2 OpenClaw接入模型服务

OpenClaw的接入配置我放在一个YAML文件里,包括模型服务地址、生成参数、执行器和报告目录几个部分。配置清晰分离之后,不同环境之间迁移只需要改这个文件。

# config.yaml model: name: qwen3.5-9b endpoint: http://127.0.0.1:8000/v1 temperature: 0.3 max_tokens: 4096 generator: type: schema-based prompt_template: ./prompts/ui_case_generator.md few_shot_examples: ./examples/ui_cases.json schema_file: ./schemas/ui_case_schema.json executor: driver: webdriver-standard browser: chromium default_timeout: 15 headless: true report: output_dir: ./reports aggregate: true

对接完成后,OpenClaw的生成层会把页面结构快照和业务需求填进Prompt模板,调用模型服务,拿到返回内容后先做一次Schema校验。校验不通过的情况下,会把错误信息拼接进新一轮Prompt,让模型自己修正。这个"自我修正"机制很重要,能显著提高一次生成通过率。我实测下来,接入重试机制后JSON解析失败率从最初的百分之十几降到了百分之三以内。

4.3 用真实场景演示一次用例生成

为了讲清楚完整流程,我拿一个虚构的内部订单管理后台举例。业务需求是:"作为订单管理员,我希望按订单号关键词搜索订单,并通过翻页确认搜索结果完整展示。"页面结构快照由浏览器驱动从订单列表页抓取,经过序列化处理后给到生成层。

OpenClaw的调用代码非常简单,生成和执行的逻辑全部封装在客户端里。

import requests from openclaw.client import OpenClawClient client = OpenClawClient.from_config("config.yaml") result = client.generate_case( page_snapshot=page_snapshot, user_story="作为订单管理员,我希望按订单号关键词搜索订单,以便快速定位特定订单", schema_file="./schemas/ui_case_schema.json" ) print(result.case_json) execution = client.execute_case(result.case_json) print(execution.report)

模型生成的用例与我预期基本一致:先进入订单列表页,在搜索框输入订单号关键字,点击搜索,等待结果加载,断言列表内出现对应订单记录。但我也发现了两处需要人工修正的问题。一是模型在等待数据加载时写了一个不存在的loading状态类名,二是缺少点击重置按钮的清理步骤。这两类问题通过人工评审补充修正即可,整体生成质量在可接受范围内。

4.4 执行与测试报告

用例生成之后,执行层会把JSON步骤翻译成标准化的浏览器操作指令。执行器内部维护了一套动作映射表,input操作对应元素框输入并触发事件,wait操作对应显式等待某个条件成立。每执行一个步骤,执行器都会记录时间戳、消耗时长和操作结果;如果步骤失败,会自动截取当时页面截图作为证据。

执行完后,聚合层会把所有步骤日志、断言结果和截图生成一份结构化报告,同时标注出用例的执行路径、失败步骤、耗时分布和失败截图索引。我通常在每天晚上定时跑一遍全量回归,第二天早上看报告,重点只关注最近新增或变更模块的用例,其他模块只要没有异常波动就不需要花时间。

这种模式下,测试人员的时间和精力被大幅释放,可以把更多注意力放在分析失败原因、补充边界场景和维护元素库这些模型做不好的事情上。

5. 踩坑实录:质量、定位、性能的排查方法

5.1 模型生成结果不稳定的调整技巧

刚开始接入模型时,最让人头疼的问题是同一段输入连续生成两次,结果可能在步骤顺序、断言粒度上差很多。排查后发现是温度参数太高,模型把"生成用例"当成了开放式的自由创作。把温度从默认值降到0.3,再去掉Prompt里那些模棱两可的修饰词,稳定性立刻改善。

还有一个稳定性的来源是少样本示例。我给模型提供的那一条完整示例,覆盖了登录、查询、分页、断言、清理全链路。模型在生成时会不自觉模仿这条示例的结构,所以示例本身的质量直接决定整个输出风格。我把示例中所有的元素标识调整成与元素库一致后,生成结果里元素标识的误用率明显下降。

如果连续多次生成结果仍然不符合预期,不要急着改Prompt。先退回一步,简化待生成的用例目标,拆成两个更小粒度的用例试试。模型在小而明确的上下文里表现通常好过大而复杂的上下文。

5.2 元素定位失败的典型场景和解决办法

执行阶段最常见的失败原因是元素定位失败。经过无数次复现和排查,我把典型场景总结为三类。第一类是动态ID,前端框架在每次渲染时生成的id都带时间戳或随机数,模型拿到的是上一次的快照,执行时ID早就变了。这类问题我通过让模型优先使用>

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

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

立即咨询