当前位置: 首页 > news >正文

Nano-Banana在软件测试中的应用:自动化测试脚本生成

Nano-Banana在软件测试中的应用:自动化测试脚本生成

最近跟几个做测试开发的朋友聊天,发现他们都在为一个事儿头疼:UI自动化测试脚本的维护成本太高了。页面稍微改个按钮位置,或者加个新字段,之前写的脚本就得跟着改,有时候改起来比重新写还费劲。

“要是能有个工具,看一眼新页面就知道该怎么测就好了。”一个朋友半开玩笑地说。

我当时就想到了最近在图像生成领域很火的Nano-Banana。这玩意儿不是能看懂图片内容,还能根据描述生成新图片吗?那反过来想,给它一张软件界面截图,让它“看懂”这个界面,然后自动生成测试脚本,这事儿理论上是不是能成?

抱着这个想法,我花了一周时间做了个实验。结果比我想象的还要好——用Nano-Banana配合一些简单的代码,真的能实现自动化测试脚本的自动生成。今天就把这个实验的过程和结果分享给大家,看看AI是怎么帮我们解决测试脚本维护这个老大难问题的。

1. 为什么测试脚本生成是个痛点?

在聊具体方案之前,我们先看看传统UI自动化测试脚本开发到底难在哪。

1.1 传统方式的三大痛点

第一,元素定位太脆弱。这是最让人头疼的问题。前端开发改个class名、加个div层级,你的XPath或者CSS选择器可能就失效了。我见过一个项目,每次发版前测试团队都要花两天时间专门修复因为UI改动而失效的测试脚本。

第二,脚本维护成本高。一个中等规模的Web应用,完整的UI自动化测试套件可能有几百个测试用例。页面结构一调整,这些用例都得跟着改。更麻烦的是,有时候你根本不知道哪个页面改了,得等到测试失败了才发现。

第三,测试覆盖不全。手动写测试脚本的时候,测试工程师往往会按照自己的理解去覆盖“重要”的功能点。但有些边缘情况、异常流程可能就被忽略了。特别是当应用越来越复杂,功能点越来越多的时候,靠人工很难保证测试的完整性。

1.2 AI能带来什么改变?

Nano-Banana这类多模态大模型有个很厉害的能力:它能“看懂”图片。给它一张软件界面的截图,它能识别出里面的按钮、输入框、下拉菜单这些UI元素,还能理解它们之间的关系。

这就很有意思了。如果我们能让AI:

  1. 看懂当前的软件界面
  2. 理解这个界面应该怎么操作
  3. 根据操作逻辑自动生成测试代码

那上面说的那些痛点,是不是就有解了?

2. 实验方案设计

我的实验思路很简单:用Nano-Banana分析软件界面截图,识别出可操作的元素和它们的功能,然后基于这些信息自动生成Python+Selenium的测试脚本。

2.1 技术选型

核心模型:Nano-Banana Pro。选它主要是因为两个原因:一是对图像内容的理解能力比较强,二是能处理比较复杂的指令。我们需要它不仅能识别出“这是个按钮”,还要能判断“这个按钮是提交表单用的”。

测试框架:Selenium + pytest。这是目前最成熟的Web自动化测试方案,社区资源丰富,遇到问题好解决。

辅助工具:Playwright用于获取页面截图和DOM结构,BeautifulSoup用于解析HTML,方便我们验证AI识别的准确性。

2.2 整体流程

整个方案的工作流程是这样的:

  1. 页面截图:用Playwright打开被测页面,截取完整截图
  2. 元素识别:把截图传给Nano-Banana,让它识别页面上的所有可交互元素
  3. 功能分析:针对每个识别出的元素,分析它的功能和使用方式
  4. 脚本生成:根据分析结果,自动生成对应的Selenium测试代码
  5. 脚本优化:对生成的代码进行整理和优化,提高可读性和可维护性

听起来有点抽象?我们直接看代码。

3. 核心实现代码

3.1 页面分析与元素识别

首先,我们需要一个函数来获取页面信息并调用Nano-Banana进行分析。这里我用的是Nano-Banana的API接口:

import base64 import requests from PIL import Image import io class PageAnalyzer: def __init__(self, api_key): self.api_key = api_key self.api_url = "https://api.example.com/v1/analyze" # 实际使用时替换为真实的API地址 def analyze_page(self, page_url, screenshot_path=None): """ 分析页面并识别UI元素 参数: page_url: 要分析的页面URL screenshot_path: 页面截图保存路径(可选) """ # 第一步:获取页面截图 from playwright.sync_api import sync_playwright with sync_playwright() as p: browser = p.chromium.launch(headless=True) page = browser.new_page() page.goto(page_url) # 等待页面加载完成 page.wait_for_load_state("networkidle") # 截取页面截图 screenshot = page.screenshot(full_page=True) if screenshot_path: with open(screenshot_path, "wb") as f: f.write(screenshot) # 获取页面HTML结构(用于后续验证) html_content = page.content() browser.close() # 第二步:调用Nano-Banana分析截图 analysis_result = self._call_nano_banana(screenshot, html_content) return { "screenshot": screenshot, "html": html_content, "analysis": analysis_result } def _call_nano_banana(self, screenshot_bytes, html_content): """ 调用Nano-Banana API分析页面 """ # 将截图转换为base64 screenshot_b64 = base64.b64encode(screenshot_bytes).decode('utf-8') # 构建分析指令 # 这里的关键是给AI明确的指令,告诉它我们要识别什么 prompt = """ 请分析这张软件界面截图,识别出所有可交互的UI元素。 对于每个元素,请提供以下信息: 1. 元素类型(按钮、输入框、下拉菜单、链接、复选框等) 2. 元素在页面中的大概位置(左上、中部、右侧等) 3. 元素的文本内容或标签(如果有) 4. 元素的可能功能(提交表单、导航、搜索、筛选等) 5. 建议的定位方式(优先使用ID,其次name,最后XPath) 页面HTML结构供参考: """ # 截取部分HTML内容,避免请求过大 html_preview = html_content[:2000] + "..." if len(html_content) > 2000 else html_content payload = { "model": "nano-banana-pro", "prompt": prompt + "\n" + html_preview, "image": screenshot_b64, "response_format": "json" } headers = { "Authorization": f"Bearer {self.api_key}", "Content-Type": "application/json" } try: response = requests.post(self.api_url, json=payload, headers=headers, timeout=60) response.raise_for_status() return response.json() except Exception as e: print(f"API调用失败: {str(e)}") return None

3.2 测试脚本生成器

拿到AI的分析结果后,下一步就是根据这些信息生成测试脚本:

class TestScriptGenerator: def __init__(self, page_url, page_title): self.page_url = page_url self.page_title = page_title self.elements = [] self.test_cases = [] def add_element(self, element_info): """ 添加识别出的UI元素 """ self.elements.append(element_info) def generate_script(self): """ 生成完整的测试脚本 """ script_lines = [] # 文件头 script_lines.append('"""') script_lines.append(f'自动化测试脚本 - {self.page_title}') script_lines.append(f'生成时间: {datetime.now().strftime("%Y-%m-%d %H:%M:%S")}') script_lines.append(f'测试页面: {self.page_url}') script_lines.append('"""\n') # 导入依赖 script_lines.append('import pytest') script_lines.append('from selenium import webdriver') script_lines.append('from selenium.webdriver.common.by import By') script_lines.append('from selenium.webdriver.support.ui import WebDriverWait') script_lines.append('from selenium.webdriver.support import expected_conditions as EC') script_lines.append('import time\n') # 测试类定义 script_lines.append(f'class Test{self.page_title.replace(" ", "").replace("-", "")}:') script_lines.append(' """') script_lines.append(f' {self.page_title}页面自动化测试') script_lines.append(' """\n') # setup和teardown方法 script_lines.append(' @pytest.fixture(scope="class")') script_lines.append(' def driver(self):') script_lines.append(' """初始化浏览器驱动"""') script_lines.append(' driver = webdriver.Chrome()') script_lines.append(' driver.maximize_window()') script_lines.append(' driver.implicitly_wait(10)') script_lines.append(' yield driver') script_lines.append(' driver.quit()\n') # 生成每个元素的测试方法 for i, element in enumerate(self.elements): if element.get('type') in ['button', 'submit']: script_lines.extend(self._generate_button_test(i, element)) elif element.get('type') in ['input', 'text', 'textarea']: script_lines.extend(self._generate_input_test(i, element)) elif element.get('type') in ['link', 'a']: script_lines.extend(self._generate_link_test(i, element)) return '\n'.join(script_lines) def _generate_button_test(self, index, element): """ 生成按钮测试代码 """ test_name = element.get('text', f'button_{index}').replace(' ', '_').lower() locator = self._get_locator(element) code = [ f' def test_{test_name}_button(self, driver):', f' """测试{element.get("text", "按钮")}功能"""', f' driver.get("{self.page_url}")', '', f' # 定位并点击按钮', f' button = driver.find_element({locator})', f' assert button.is_displayed(), "按钮未显示"', f' assert button.is_enabled(), "按钮不可用"', f' ', f' # 记录点击前的状态(可根据实际需求调整)', f' original_url = driver.current_url', f' ', f' # 执行点击', f' button.click()', f' time.sleep(1) # 等待页面响应', f' ', f' # 验证点击效果', f' # 这里可以根据按钮的实际功能添加更多验证', f' if "{element.get("function", "")}".find("提交") >= 0:', f' # 如果是提交按钮,检查是否有成功提示', f' pass', f' elif "{element.get("function", "")}".find("导航") >= 0:', f' # 如果是导航按钮,检查URL是否变化', f' assert driver.current_url != original_url, "导航未生效"', f' ', f' print(f"按钮测试通过: {element.get(\"text\", \"\")}")', '' ] return code def _generate_input_test(self, index, element): """ 生成输入框测试代码 """ test_name = element.get('label', f'input_{index}').replace(' ', '_').lower() locator = self._get_locator(element) # 根据输入框类型生成不同的测试数据 input_type = element.get('input_type', 'text') test_data = self._get_test_data_for_input(input_type) code = [ f' def test_{test_name}_input(self, driver):', f' """测试{element.get("label", "输入框")}功能"""', f' driver.get("{self.page_url}")', '', f' # 定位输入框', f' input_field = driver.find_element({locator})', f' assert input_field.is_displayed(), "输入框未显示"', f' assert input_field.is_enabled(), "输入框不可用"', f' ', f' # 清空原有内容(如果有)', f' input_field.clear()', f' ', f' # 输入测试数据', f' test_value = "{test_data}"', f' input_field.send_keys(test_value)', f' ', f' # 验证输入是否成功', f' assert input_field.get_attribute("value") == test_value, "输入内容不匹配"', f' ', f' print(f"输入框测试通过: {element.get(\"label\", \"\")}")', '' ] return code def _get_locator(self, element): """ 根据元素信息生成定位器 """ # 这里简化处理,实际可以根据AI的建议选择最佳定位方式 if element.get('id'): return f'By.ID, "{element["id"]}"' elif element.get('name'): return f'By.NAME, "{element["name"]}"' else: # 使用XPath作为备选 text = element.get('text', element.get('label', '')) if text: return f'By.XPATH, f"//*[contains(text(), \\"{text}\\")]"' else: return 'By.XPATH, "//*"' def _get_test_data_for_input(self, input_type): """ 根据输入框类型返回测试数据 """ test_data_map = { 'text': '测试文本', 'email': 'test@example.com', 'password': 'Test123!@#', 'number': '123', 'tel': '13800138000', 'date': '2024-01-01', 'search': '搜索关键词' } return test_data_map.get(input_type, '测试数据')

3.3 完整的工作流程示例

把上面的组件组合起来,就是一个完整的测试脚本生成流程:

def generate_test_script_for_page(page_url, api_key): """ 为指定页面生成测试脚本 """ print(f"开始分析页面: {page_url}") # 初始化分析器 analyzer = PageAnalyzer(api_key) # 分析页面 print("正在获取页面截图并分析...") result = analyzer.analyze_page(page_url, "page_screenshot.png") if not result or not result.get('analysis'): print("页面分析失败") return None # 解析分析结果 analysis = result['analysis'] page_title = analysis.get('page_title', 'UnknownPage') # 初始化脚本生成器 generator = TestScriptGenerator(page_url, page_title) # 添加识别出的元素 print(f"识别到 {len(analysis.get('elements', []))} 个UI元素") for element in analysis.get('elements', []): generator.add_element(element) # 生成测试脚本 print("正在生成测试脚本...") test_script = generator.generate_script() # 保存脚本文件 filename = f"test_{page_title.lower().replace(' ', '_')}.py" with open(filename, 'w', encoding='utf-8') as f: f.write(test_script) print(f"测试脚本已生成: {filename}") print(f"包含 {len(analysis.get('elements', []))} 个测试用例") return filename # 使用示例 if __name__ == "__main__": # 替换为你的API密钥和要测试的页面 API_KEY = "your_api_key_here" TEST_PAGE = "https://example.com/login" script_file = generate_test_script_for_page(TEST_PAGE, API_KEY) if script_file: print("\n生成的脚本可以直接运行:") print(f"pytest {script_file} -v")

4. 实际效果展示

我拿几个常见的页面做了测试,看看生成的效果怎么样。

4.1 登录页面测试脚本生成

首先试了一个典型的登录页面。AI识别出了用户名输入框、密码输入框、登录按钮、记住密码复选框和注册链接。

生成的测试脚本包含了:

  • 测试用户名输入框能否正常输入
  • 测试密码输入框能否正常输入(并验证是否为密码类型)
  • 测试登录按钮的点击功能
  • 测试记住密码复选框的选中状态切换
  • 测试注册链接能否正确跳转

最让我惊喜的是,AI还“注意到”了密码输入框旁边那个“显示密码”的小眼睛图标,并为它生成了一个测试用例,验证点击后密码是否可见。

4.2 电商商品列表页

接着试了一个电商网站的商品列表页。这个页面元素更多更复杂:搜索框、分类筛选、排序下拉框、商品卡片、分页控件等等。

AI不仅识别出了这些元素,还根据它们的功能生成了相应的测试:

  • 搜索功能测试:输入关键词,验证搜索结果
  • 筛选功能测试:选择分类,验证商品列表更新
  • 排序测试:切换排序方式,验证商品顺序变化
  • 分页测试:点击下一页,验证页面切换

对于商品卡片,AI建议的测试点是:验证图片加载正常、价格显示正确、加入购物车按钮可用。

4.3 后台管理系统表单

最后试了一个后台管理系统的数据录入表单。这种表单通常有很多字段,各种类型的输入框、选择器、日期选择器等。

AI的表现依然不错:

  • 正确识别了文本输入框、数字输入框、邮箱输入框等不同类型
  • 对下拉选择器,生成了选择不同选项的测试
  • 对日期选择器,生成了选择日期的测试
  • 对富文本编辑器,生成了输入和格式设置的测试(虽然比较简单)
  • 对表单的提交和重置按钮都生成了相应的测试

5. 优势与局限性

5.1 明显的优势

大幅降低脚本编写成本。以前写一个中等复杂度页面的测试脚本,熟练的测试工程师也要半天到一天。用这个方案,从截图到生成可运行的脚本,整个过程不超过5分钟。

自动覆盖边缘情况。AI在分析页面时会注意到一些人工可能忽略的元素,比如那些默认隐藏、需要特定操作才会出现的控件。这有助于提高测试的覆盖率。

易于维护和更新。当页面改版时,只需要重新运行一次生成流程,就能得到更新后的测试脚本。不需要人工去一个个修改定位器。

降低技术门槛。即使是不太熟悉Selenium和编程的测试人员,也能通过这个工具快速生成基础测试脚本,然后再根据需要进行调整。

5.2 当前的局限性

元素定位可能不够精确。AI建议的定位方式有时候不是最优的,特别是对于动态生成的内容,XPath可能会很脆弱。生成的脚本可能需要人工调整定位策略。

无法理解业务逻辑。AI能识别“这是一个提交按钮”,但它不知道点击这个按钮会触发什么业务规则、应该验证什么业务结果。这部分还是需要人工补充。

处理复杂交互有难度。对于拖拽、滑动、右键菜单等复杂交互,AI生成的测试代码可能比较基础,需要人工优化。

依赖页面视觉一致性。如果页面用了大量自定义控件,或者视觉设计比较非常规,AI可能无法准确识别某些元素的类型和功能。

6. 实际应用建议

如果你也想在项目中尝试这个方案,我有几个建议:

先从简单的页面开始。登录页、列表页、详情页这些结构相对规范的页面是很好的起点。等流程跑通了,再尝试更复杂的页面。

生成的脚本要人工review。不要完全依赖AI生成的代码。一定要有人检查一下定位器是否可靠,测试逻辑是否合理,断言是否充分。

结合人工编写的测试。把AI生成的测试作为基础覆盖,再针对核心业务逻辑补充人工编写的测试用例。两者结合效果更好。

建立页面变更监控。可以设置定时任务,定期对关键页面重新生成测试脚本,并与之前的版本对比。如果发现脚本差异较大,可能意味着页面有较大改动,需要重点关注。

积累和优化prompt。AI的分析质量很大程度上取决于你给的指令。在实际使用中,不断调整和优化你的prompt,让AI更好地理解你的需求。

7. 总结

用Nano-Banana生成自动化测试脚本,听起来像是个黑科技,实际试下来发现确实有用。它不能完全替代测试工程师,但能帮我们省掉很多重复、机械的编码工作。

我特别喜欢这个方案的一点是,它让测试脚本的维护变得简单了。页面改版不再是让人头疼的事,重新生成一下脚本,大部分问题就解决了。测试工程师可以把更多时间花在设计测试场景、分析测试结果这些更有价值的事情上。

当然,现在的方案还有很多可以改进的地方。比如可以加入对测试数据的管理,可以集成到CI/CD流程中,可以支持更多类型的应用(移动端、桌面端)等等。但作为一个起点,我觉得这个方向很有潜力。

如果你也在为测试脚本的维护头疼,不妨试试这个思路。不一定非要用Nano-Banana,现在很多多模态大模型都有类似的能力。关键是把AI当成一个助手,让它帮我们处理那些它擅长的事情,我们专注在它不擅长的事情上。

技术总是在解决实际问题的过程中进步的。测试领域的自动化已经走了很远,现在AI又给我们带来了新的可能性。挺期待看到这个方向后续的发展的。


获取更多AI镜像

想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。

http://www.cnnetsun.cn/news/1310512.html

相关文章:

  • 手把手教你用flv.js实现WebSocket直播流播放(附完整测试代码)
  • 从Windows转Mac必看!对照表式整理两系统快捷键差异(含M系列芯片适配问题)
  • 音频处理实战:如何用EQ参数整定优化你的音乐作品(避坑指南)
  • DeEAR语音情感识别实操手册:自定义阈值导出‘高唤醒预警’或‘低自然度告警’事件
  • 二阶系统动态特性揭秘:如何通过改变R/C值优化阶跃响应?
  • 结构光3D测量实战:如何用HPF模型搞定高动态范围表面重建(附完整代码)
  • 雄迈摄像头开发避坑大全:截屏无声/录像卡顿的7个解决方案
  • 3个技术民主化工具让用户实现Windows/Office正版化自由
  • Nanobot智能写作助手:内容生成与风格优化
  • Stable Yogi Leather-Dress-Collection新手指南:Streamlit界面操作与错误排查手册
  • 利用快马ai一键生成quartus ii安装向导,三步搞定fpga开发环境搭建
  • Z-Image-Turbo-辉夜巫女惊艳效果展示:LoRA微调下高还原度巫女角色图集
  • Qwen3-ASR-0.6B在游戏中的语音交互功能实现
  • wan2.1-vae惊艳案例:生成可直接用于3D建模参考的正交视角线稿
  • TQVaultAE:解放泰坦之旅玩家的装备管理革命
  • AI字幕工具AutoSubs:本地化处理与多平台兼容的智能解决方案
  • Ostrakon-VL-8B在单片机系统中的应用前瞻:云端视觉AI赋能边缘设备
  • 基于立创开发板的红外火焰传感器模块驱动移植与实战应用
  • Ncorr数字图像相关技术全攻略:从原理到工程实践
  • 热电阻接线方式全解析:两线、三线、四线制到底怎么选?
  • 从Skia到GPU:OpenGL与Mesa在图形栈中的协同与定位
  • 向日葵远程控制安全事件真相:官方辟谣与行业影响分析
  • 造相Z-Image与Stable Diffusion对比:轻量、高效、中文友好的新选择
  • FireRed-OCR Studio惊艳效果:无框线表格+LaTeX公式Markdown输出实测
  • AD9361寄存器配置全解析:从ENSM状态机到滤波器设计的实战指南
  • 静息态fMRI数据分析实战:从BOLD信号到功能连接的全流程解析(附避坑指南)
  • Windows用户必看:PaddleOCR PDF转Word完整避坑指南(附Shapely安装解决方案)
  • Johnson算法实战:如何用Python优化流水线作业调度(附完整代码)
  • RK3576、RK3588、RK3568:三款主流AIoT芯片的精准选型与场景适配指南
  • 泰凌微TLSR825X定时器实战:从硬件配置到软件轮询的完整指南