返回顶部
热门问答 更多热门问答
技术文章 更多技术文章

初步调研|基于AI的自动化脚本自愈方案

[复制链接]
链载Ai 显示全部楼层 发表于 昨天 19:26 |阅读模式 打印 上一主题 下一主题



背景

当前UI自动化测试脚本的稳定性受多种因素影响,导致执行失败率较高,主要失败原因包括:

1.元素定位失效:前端属性(ID/Class/XPath)动态变更,导致脚本无法识别元素

2.页面结构重构:DOM层级或组件库升级引发原有定位策略失效

3.环境问题:网络延迟、浏览器版本差异等造成执行中断

4.业务逻辑变更:需求调整导致流程变化,原有用例不再适用

所以引入AI辅助的自愈机制,希望通过AI 实现智能定位修复,通过AI识别页面结构变化,自动生成备选选择器,自动调整定位策略,以适应前端变更,从而减少人工干预,降低维护成本降低,提高脚本稳定性。




整体方案

根据UI自动化执行失败的原因,制定不同的修复策略,具体如下

本文主要分享通过调用AI api 根据错误原因,推荐心得元素定位器列表,逐一验证新的元素定位器,验证通过则修改脚本。



AI工具选择

DeepSeek API开放平台地址:https://platform.deepseek.com/usage

调用方式:

importrequestsAPI_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数据返回




脚本调整

1. 配置文件 config.ini

配置文件内需要配置 deepseek的 api地址、api key信息,可见deepseek的api开放平台

AI_API_KEY=Bearersk-keyxxxx#需要申请API_URL=https://api.deepseek.com/v1/chat/completions

2. 自愈脚本self_healing_locator.py

1. 构建promot模版

2. 调用AI API输出推荐选择器列表

3. 遍历校验候选选择器有效性,验证通过则修改脚本;

importreimportrequestsfromplaywright.sync_apiimportPagefromcommon.rwConfigimportrwConfigfromcommon.logimportlogger# 获取配置文件信息AI_API_KEY = rwConfig().getConfigOption(option='AI_API_KEY', section="common")API_URL = rwConfig().getConfigOption(option='API_URL', section="common")classHealer: def__init__(self, page: Page):    self.page = page defdeepseek(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}") # 返回推荐列表 returnselector_list
exceptExceptionase: logger.info(f"API调用失败:{str(e)}") return[] deflocator_prompt(self, pass_selector:str,failed_selector:str) ->str: """构建元素定位提示词模板""" # 获取正确元素区域的页面内容 dom_snippet =self.get_html_around_element(pass_selector) # logger.info(f"截断dom内容: {dom_snippet}") returnf""" 请为Playwright测试生成3个可靠的元素定位器,要求: 1. 代替定位失败的选择器:{failed_selector} 2. 基于当前页面片段(可能被截断):{dom_snippet}
输出content要求: - 按稳定性优先级排序,剔除需要开发人员参与的定位方式 - 使用CSS或XPath格式 - 输出为Python列表格式,如:["1", "2"],剔除其他文案,仅保留list内容 """ defheal_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) # 验证选择器有效性 forselectorinelements: logger.info(f"第【{i+1}】次验证选择器有效性:{selector}") ifself._try_selector(selector): # 更新测试脚本文件 logger.info(f"更新测试脚本文件:{test_file}失败元素:{failed_selector}新定位器:{selector}") self.update_file(test_file, failed_selector, selector) returnTrue else: i +=1 ifi >3: logger.info(f"AI推荐的选择器均 验证失败") returnFalse
logger.info(f"未找到有效定位器:{failed_selector}") returnFalse

defget_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)
ifelement_index == -1: logger.info("关键元素 未找到") returnNone
# 计算截取范围 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]
returnsurrounding_html deftry_selector(self, selector:str) ->bool: """验证选择器有效性""" try: self.page.wait_for_selector(selector, timeout=3000) logger.info(f"选择器 有效:{selector}") returnTrue except: logger.info(f"选择器 无效:{selector}") returnFalse defupdate_file(self, file_path:str, old:str, new:str): """更新测试脚本文件""" withopen(file_path,"r")asf: content = f.read()
updated = re.sub( rf'([\'"])({re.escape(old)})([\'"])', lambdam:f"{m.group(1)}{new}{m.group(3)}", content ) logger.info(f"更新后的内容:{updated}") withopen(file_path,"w")asf: f.write(updated)

3. 测试demo

importpytestfromplaywright.sync_apiimportPage, expectfromcommon.self_healing_locatorimportSaucedemoHealerfromcommon.rwConfigimportrwConfigfromconftestimport*URL ="https://xxxxxx/sso"headless=bool(int(rwConfig().getConfigOption(option='headless')))@pytest.fixture(scope="module")defpage(): withsync_playwright()asplaywright:    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)   yieldpage    browser.close()
@pytest.fixturedefhealer(page): yieldHealer(page)
deftest_checkout_flow(page, healer: Healer):
try: page.goto(URL) visible = page.get_by_role("heading", name="手机密码登录").is_visible() ifnotvisible: # 切换到手机号密码登录页面 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() exceptExceptionase: if"#pwd"instr(e): # 触发自愈流程:传入正确元素、失败元素 ifhealer.heal_element("#phone","#pwd", __file__): pytest.fail("元素定位已自动修复,请重新运行测试") else: pytest.fail("元素定位修复失败 END") raisee


当前阶段遗留问题:

1. 部分页面的html内容获取失败,导致推荐选择器获取失败

2.自愈脚本如何快速运用到全局case中

3.在pytest中,使用的是--reruns或其他重试机制(如pytest-rerunfailures),所以重试时不会自动加载修改后的脚本,因为:

  • Python 在首次导入模块时会将其编译为字节码(.pyc),并缓存在__pycache__目录中。

  • 重试时pytest仍会使用内存中已加载的模块(即第一次执行时的脚本版本),不会重新读取磁盘上的修改


回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

链载AI是专业的生成式人工智能教程平台。提供Stable Diffusion、Midjourney AI绘画教程,Suno AI音乐生成指南,以及Runway、Pika等AI视频制作与动画生成实战案例。从提示词编写到参数调整,手把手助您从入门到精通。
  • 官方手机版

  • 微信公众号

  • 商务合作

  • Powered by Discuz! X3.5 | Copyright © 2025-2025. | 链载Ai
  • 桂ICP备2024021734号 | 营业执照 | |广西笔趣文化传媒有限公司|| QQ