微信扫码
添加专属顾问
我要投稿
AI助力UI自动化测试脚本自愈,智能解决元素定位失效等四大难题,显著提升脚本稳定性。 核心内容: 1. UI自动化测试脚本失败的四大主要原因分析 2. 基于Deepseek API的AI自愈方案设计与实现 3. 具体配置和脚本调整的实践指南
当前UI自动化测试脚本的稳定性受多种因素影响,导致执行失败率较高,主要失败原因包括:
1.元素定位失效:前端属性(ID/Class/XPath)动态变更,导致脚本无法识别元素
2.页面结构重构:DOM层级或组件库升级引发原有定位策略失效
3.环境问题:网络延迟、浏览器版本差异等造成执行中断
4.业务逻辑变更:需求调整导致流程变化,原有用例不再适用
所以引入AI辅助的自愈机制,希望通过 AI 实现智能定位修复,通过AI 识别页面结构变化,自动生成备选选择器,自动调整定位策略,以适应前端变更,从而减少人工干预,降低维护成本降低,提高脚本稳定性。
根据UI自动化执行失败的原因,制定不同的修复策略,具体如下
本文主要分享通过调用AI api 根据错误原因,推荐心得元素定位器列表,逐一验证新的元素定位器,验证通过则修改脚本。
调用方式:
import requests API_KEY = "your_api_key" url = "https://api.deepseek.com/v1/chat/completions" headers = { "Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json" } payload = { "model": "deepseek-chat", "messages": [ {"role": "user", "content": "请解释Transformer的注意力机制"} ], "temperature": 0.7, "max_tokens": 1000 } response = requests.post(url, json=payload, headers=headers) print(response.json())
Deepseek API 返回数据类型:支持json数据返回
AI_API_KEY = Bearer sk-keyxxxx #需要申请API_URL = https://api.deepseek.com/v1/chat/completions
2. 自愈脚本 self_healing_locator.py
1. 构建promot模版
2. 调用AI API输出推荐选择器列表
3. 遍历校验候选选择器有效性,验证通过则修改脚本;
import re
import requests
from playwright.sync_api import Page
from common.rwConfig import rwConfig
from common.log import logger
# 获取配置文件信息
AI_API_KEY = rwConfig().getConfigOption(option='AI_API_KEY', section="common")
API_URL = rwConfig().getConfigOption(option='API_URL', section="common")
class Healer:
def __init__(self, page: Page):
self.page = page
def deepseek(self, prompt: str) -> list:
"""调用AI API 生成定位器"""
headers = {
"Authorization": AI_API_KEY,
"Content-Type": "application/json"
}
# 调用deepseek API
payload = {
"model": "deepseek-chat",
"messages": [
{"role": "user", "content": prompt}
],
"temperature": 0.7,
"max_tokens": 1000
}
try:
response = requests.post(API_URL, headers=headers, json=payload)
logger.info(f"API调用成功: {response.json()['choices'][0]['message']['content']}")
selector_list = eval(response.json()['choices'][0]['message']['content'])
logger.info(f"AI推荐定位器列表: {selector_list}")
# 返回推荐列表
return selector_list
except Exception as e:
logger.info(f"API调用失败: {str(e)}")
return []
def locator_prompt(self, pass_selector:str,failed_selector:str) ->str:
"""构建元素定位提示词模板"""
# 获取正确元素区域的页面内容
dom_snippet =self.get_html_around_element(pass_selector)
# logger.info(f"截断dom内容: {dom_snippet}")
return f"""
请为Playwright测试生成3个可靠的元素定位器,要求:
1. 代替定位失败的选择器:{failed_selector}
2. 基于当前页面片段(可能被截断):{dom_snippet}
输出content要求:
- 按稳定性优先级排序,剔除需要开发人员参与的定位方式
- 使用CSS或XPath格式
- 输出为Python列表格式,如:["1", "2"],剔除其他文案,仅保留list内容
"""
def heal_element(self,pass_selector:str,failed_selector:str, test_file:str) ->bool:
"""执行自愈流程"""
i = 0
prompt =self.locator_prompt(pass_selector,failed_selector)
logger.info(f"生成定位器提示词: {prompt}")
# 调用AI API 生成定位器
elements =self.deepseek(prompt)
# 验证选择器有效性
for selector in elements:
logger.info(f"第【{i+1}】次验证选择器有效性: {selector}")
if self._try_selector(selector):
# 更新测试脚本文件
logger.info(f"更新测试脚本文件: {test_file} 失败元素: {failed_selector} 新定位器: {selector}")
self.update_file(test_file, failed_selector, selector)
return True
else:
i += 1
if i > 3:
logger.info(f"AI推荐的选择器均 验证失败")
return False
logger.info(f"未找到有效定位器: {failed_selector}")
return False
def get_html(self, selector, chars_before=2000, chars_after=10000):
# 获失败元素局部页面的HTML
full_html = self.page.content()
# 获取元素的outerHTML和位置
element_html = self.page.locator(selector).evaluate('el => el.outerHTML')
element_index = full_html.find(element_html)
if element_index == -1:
logger.info("关键元素 未找到")
return None
# 计算截取范围
start = max(0, element_index - chars_before)
end = min(len(full_html), element_index + len(element_html) + chars_after)
# 截取页面片段
surrounding_html = full_html[start:end]
return surrounding_html
def try_selector(self, selector: str) -> bool:
"""验证选择器有效性"""
try:
self.page.wait_for_selector(selector, timeout=3000)
logger.info(f"选择器 有效: {selector}")
return True
except:
logger.info(f"选择器 无效: {selector}")
return False
def update_file(self, file_path: str, old: str, new: str):
"""更新测试脚本文件"""
with open(file_path, "r") as f:
content = f.read()
updated = re.sub(
rf'([\'"])({re.escape(old)})([\'"])',
lambda m: f"{m.group(1)}{new}{m.group(3)}",
content
)
logger.info(f"更新后的内容: {updated}")
with open(file_path, "w") as f:
f.write(updated)
3. 测试demo
import pytest
from playwright.sync_api import Page, expect
from common.self_healing_locator import SaucedemoHealer
from common.rwConfig import rwConfig
from conftest import *
URL = "https://xxxxxx/sso"
headless=bool(int(rwConfig().getConfigOption(option='headless')))
def page():
with sync_playwright() as playwright:
browser = playwright.chromium.launch(headless=headless)
#保存登录信息
# context = browser.new_context(storage_state="./data/state.json")
context = browser.new_context(
page=context.new_page()
page.goto(URL)
yield page
browser.close()
def healer(page):
yield Healer(page)
def test_checkout_flow(page, healer: Healer):
try:
page.goto(URL)
visible = page.get_by_role("heading", name="手机密码登录").is_visible()
if not visible:
# 切换到手机号密码登录页面
time.sleep(1)
page.locator("xxwc-togger-sign div").nth(1).click()
# 输入手机号
page.locator("#phone").fill("xxxxxx")
# 输入密码
page.locator("#pwd").fill("xxxxxx")
# 点击登录按钮
page.locator(".xxx-button-login").click()
except Exception as e:
if "#pwd" in str(e):
# 触发自愈流程:传入正确元素、失败元素
if healer.heal_element("#phone","#pwd", __file__):
pytest.fail("元素定位已自动修复,请重新运行测试")
else:
pytest.fail("元素定位修复失败 END")
raise e
当前阶段遗留问题:
1. 部分页面的html内容获取失败,导致推荐选择器获取失败
2.自愈脚本如何快速运用到全局case中
3. 在 pytest
中,使用的是 --reruns
或其他重试机制(如 pytest-rerunfailures
),所以重试时不会自动加载修改后的脚本,因为:
Python 在首次导入模块时会将其编译为字节码(.pyc
),并缓存在 __pycache__
目录中。
重试时,pytest
仍会使用内存中已加载的模块(即第一次执行时的脚本版本),不会重新读取磁盘上的修改
53AI,企业落地大模型首选服务商
产品:场景落地咨询+大模型应用平台+行业解决方案
承诺:免费POC验证,效果达标后再合作。零风险落地应用大模型,已交付160+中大型企业
2025-09-02
腾讯 ima 上新:1.11.0 AI播客音色优化和知识库导入网页链接
2025-09-02
阿里云 CIO 蒋林泉:AI 大模型时代,我们如何用 RIDE 实现 RaaS 的首次落地?
2025-09-02
有了这个大模型,真正的智能运维AIOps时代即将来临
2025-09-02
突破企业AI落地的瓶颈:LangGraph × OceanBase 的融合数据层深度实践与解析(附源码)
2025-09-02
腾讯元宝搜索实践:大模型时代,AI 如何让搜索焕发新生
2025-09-02
今天,AI内容新规正式实施,这次不注意是真的会违法。
2025-09-01
OpenAI gpt-realtime 与 Realtime API 重磅升级,语音智能体迎来生产级时代
2025-09-01
Google的AI应用版图,我可以做到的最详细的版本
2025-08-21
2025-06-21
2025-08-21
2025-08-19
2025-06-07
2025-06-12
2025-06-19
2025-06-13
2025-07-29
2025-06-15
2025-09-02
2025-08-28
2025-08-28
2025-08-28
2025-08-28
2025-08-27
2025-08-26
2025-08-25