1. 项目概述:当自动化测试遇见大模型
最近在搞一个项目,需要为我们的Web产品做大量的回归测试。传统的自动化测试脚本编写,大家懂的都懂,要么是让测试同学吭哧吭哧地写Selenium或者Playwright脚本,要么是让开发同学在写业务代码之余再写一堆测试代码,效率低不说,维护成本还高。尤其是当UI或者业务流程稍微变动一下,一堆脚本就得跟着改,测试同学和开发同学都苦不堪言。
就在我们为这事儿头疼的时候,团队里有人提了个想法:现在大模型这么火,能不能让它来帮我们写测试脚本?我们只需要用自然语言描述一下测试场景,比如“用户登录后,在首页搜索商品‘手机’,并加入购物车”,然后AI就能自动生成可执行的浏览器自动化测试代码。这听起来简直是测试工程师的“梦中情工”。
经过一番调研和尝试,我们最终把目光锁定在了Nanbeige 4.1-3B这个模型上。这是一个参数规模为40亿的中英双语大语言模型,在代码生成和理解方面表现不错,而且对中文自然语言指令的响应很友好。最关键的是,它的体量相对适中,无论是通过API调用还是在本地部署,成本和可控性都比动辄百亿、千亿参数的大模型要友好得多。
这个项目的核心,就是搭建一个“自然语言到测试脚本”的转换管道。我们不再需要直接编写复杂的定位器(XPath、CSS Selector)和流程控制逻辑,而是把测试意图用大白话说出来,交给AI去理解和生成。这不仅仅是“偷懒”,更是对测试工作流的一次根本性变革。它降低了自动化测试的门槛,让业务专家、产品经理也能参与到测试用例的设计和验证中来,而不仅仅是专业的测试开发工程师。
接下来,我会详细拆解我们是如何将浏览器自动化测试与Nanbeige 4.1-3B结合,构建出一套智能测试脚本生成工具的。整个过程涉及环境搭建、模型部署、提示词工程、脚本后处理以及最终的集成与优化。我会把每一步的思考、踩过的坑和最终验证有效的方案都分享出来。
2. 核心思路与技术选型解析
2.1 为什么是“自然语言生成测试脚本”?
在深入技术细节之前,我们先聊聊为什么这个方向值得投入。传统的测试脚本编写存在几个明显的痛点:
- 技能门槛高:编写稳定的自动化测试脚本,不仅需要掌握编程语言(如Python、Java),还需要精通测试框架(如Selenium、Cypress、Playwright)和复杂的页面元素定位技术。这对于非开发背景的测试人员或业务人员来说,学习曲线陡峭。
- 编写与维护成本高:一个完整的测试用例脚本,往往包含大量的初始化、元素定位、操作步骤、断言和清理工作。编写耗时,且当页面结构(DOM)发生变化时,脆弱的定位器很容易失效,导致脚本“崩掉”,维护工作量巨大。
- 沟通与理解偏差:产品经理或业务方用自然语言编写的测试用例,需要测试工程师人工“翻译”成代码。这个过程中可能存在理解偏差,导致实现的脚本与原始需求不符。
而“自然语言生成测试脚本”的思路,旨在用AI作为“翻译官”和“代码生成器”,直接弥合自然语言需求与可执行代码之间的鸿沟。它的理想状态是:输入一句话,输出一段可直接运行或稍作调整即可运行的测试脚本。这能极大提升测试用例的产出速度,让测试人员更专注于测试设计、边界案例挖掘和结果分析这些更具创造性的工作。
2.2 模型选型:为什么选择Nanbeige 4.1-3B?
市面上可用于代码生成的大模型很多,比如GPT-4、Claude、DeepSeek-Coder等。我们选择Nanbeige 4.1-3B,是基于以下几个实际的考量:
- 成本与可控性:GPT-4等闭源模型的API调用费用不菲,且存在数据出境、响应延迟、服务稳定性等潜在风险。对于企业内部可能涉及敏感业务数据的测试用例生成,将数据发送到外部云端存在安全隐患。Nanbeige 4.1-3B是一个开源模型,我们可以将其部署在内网或本地环境,实现数据的完全私有化,长期来看成本也更可控。
- 模型能力与体量平衡:40亿参数的模型,在代码生成任务上已经表现出足够的能力。它比一些更小的模型(如7B、13B)在理解复杂指令和生成较长、结构正确的代码方面更可靠,同时又比70B、千亿级模型所需的计算资源(GPU显存、推理速度)要友好得多。对于大多数Web自动化测试脚本(通常不超过100行代码)的生成任务来说,这个规模是“性价比”很高的选择。
- 对中文的友好支持:我们的测试用例描述和团队沟通主要使用中文。Nanbeige 4.1-3B在中文理解和生成上进行了优化,这对于我们构建基于中文自然语言的指令系统至关重要。我们不必费心将中文用例翻译成英文再喂给模型,减少了中间环节和误差。
- 社区与生态:作为国内主流的开源大模型之一,Nanbeige有着活跃的社区和相对完善的工具链支持(如Transformers库、vLLM等),便于我们进行部署、调试和集成。
注意:模型选型没有绝对的对错,取决于团队的具体需求、资源和技术栈。如果你的团队更熟悉英文,且对生成代码的复杂度和准确性要求极高,并能承担相应的成本,那么GPT-4或Claude可能是更好的起点。但对于希望自主可控、快速验证想法并控制成本的大多数团队,从类似Nanbeige 4.1-3B这样的优秀开源模型入手,是一个非常务实的选择。
2.3 整体架构设计
我们的智能测试脚本生成系统,其核心流程可以概括为以下几步:
自然语言测试用例 -> 模型推理引擎 -> 原始代码输出 -> 代码后处理与验证 -> 可执行测试脚本- 输入层:接收用户以自然语言描述的测试场景。例如:“测试用户登录功能:使用账号
test@example.com和密码123456登录系统,验证登录成功后页面跳转到仪表盘,并且右上角显示用户名‘测试用户’。” - 处理与推理层:这是核心。系统会将自然语言描述,结合我们精心设计的“提示词模板”(Prompt Template),构造成一个完整的指令,发送给部署好的Nanbeige 4.1-3B模型进行推理。提示词模板中包含了角色设定、任务描述、输出格式要求、示例等关键信息,用于引导模型生成符合我们预期的代码。
- 输出与后处理层:模型会生成一段代码(通常是Python)。这段原始代码可能包含一些小错误、多余的注释或不规范的格式。后处理模块会对其进行语法检查、简单格式化,并尝试注入一些必要的依赖(如缺失的import语句)。更高级的后处理还可以尝试用AST(抽象语法树)解析代码,确保其结构基本正确。
- 验证与交付层:生成的脚本不会直接投入生产使用。我们会提供一个预览界面,让测试工程师审查生成的代码,进行微调(如修正某个定位器),然后手动或自动触发一次试运行。试运行成功,该脚本才被标记为可用,并可以集成到CI/CD流水线中。
整个系统的技术栈我们选择了Python作为主语言,因为它在大模型应用和自动化测试领域都有丰富的生态。Web框架采用FastAPI提供生成服务的API接口,前端用简单的Vue.js构建一个操作界面。模型部署方面,我们试验了两种方案:一是使用transformers库在本地GPU服务器上进行推理;二是使用vLLM部署以提高吞吐量,后者在需要处理并发生成请求时表现更佳。
3. 环境搭建与模型部署实战
3.1 基础环境准备
工欲善其事,必先利其器。第一步是准备好运行模型所需的环境。由于Nanbeige 4.1-3B是一个约8GB(FP16精度)的模型,我们需要一台配备有足够显存的GPU服务器。经过测试,一张16GB显存的显卡(如NVIDIA T4、RTX 4080)可以流畅地进行推理。
我们的基础软件环境如下:
- 操作系统:Ubuntu 22.04 LTS
- Python版本:3.10(这是一个在稳定性和新特性之间取得较好平衡的版本)
- CUDA工具包:12.1(需与显卡驱动和后续安装的PyTorch版本匹配)
- 深度学习框架:PyTorch 2.1+
首先,创建并激活一个独立的Python虚拟环境,这是避免包冲突的最佳实践。
# 创建虚拟环境 python3.10 -m venv nanbeige-test-env # 激活虚拟环境 source nanbeige-test-env/bin/activate接着,安装PyTorch。务必去PyTorch官网根据你的CUDA版本获取正确的安装命令。例如,对于CUDA 12.1:
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121然后,安装核心的模型加载和推理库transformers,以及加速库accelerate。
pip install transformers accelerate为了后续的Web服务,我们也一并安装fastapi和uvicorn。
pip install fastapi uvicorn3.2 两种模型部署方案对比与实施
部署Nanbeige 4.1-3B模型,我们主要尝试了两种主流方案:使用Hugging Facetransformers库进行直接加载,以及使用vLLM进行高性能部署。
方案一:使用Transformers库直接加载(适合原型验证与低频使用)
这是最简单直接的方式。我们从Hugging Face模型仓库下载模型,并用pipeline进行调用。
from transformers import AutoTokenizer, AutoModelForCausalLM, pipeline import torch # 指定模型路径(可以是Hugging Face模型ID,如 `nanbeige/nanbeige-4.1-3b`,也可以是本地路径) model_name = "nanbeige/nanbeige-4.1-3b" # 加载tokenizer和模型 tokenizer = AutoTokenizer.from_pretrained(model_name) model = AutoModelForCausalLM.from_pretrained( model_name, torch_dtype=torch.float16, # 使用半精度减少显存占用 device_map="auto", # 自动将模型层分配到可用的GPU/CPU上 trust_remote_code=True # 信任远程代码,某些模型需要 ) # 创建文本生成pipeline text_generation_pipe = pipeline( "text-generation", model=model, tokenizer=tokenizer, device_map="auto" )这种方式上手快,但缺点是在并发请求下性能较差,因为每次生成都需要重新计算整个上下文,并且transformers的默认实现并非为高吞吐量优化。如果你的场景是测试人员偶尔手动生成一两个脚本,这个方案完全够用。
方案二:使用vLLM部署(适合生产环境与API服务)
当我们需要提供一个供多人同时使用的API服务时,vLLM是更好的选择。它采用了PagedAttention等优化技术,能极大提高推理速度和吞吐量,并高效管理显存。
首先安装vLLM:
pip install vLLM然后,可以编写一个简单的FastAPI应用来提供生成服务:
# app.py from fastapi import FastAPI from pydantic import BaseModel from vllm import LLM, SamplingParams import os app = FastAPI() # 定义请求体模型 class GenerationRequest(BaseModel): prompt: str max_tokens: int = 1024 temperature: float = 0.1 # 温度调低,使生成结果更确定,更适合代码生成 # 在应用启动时加载模型(单例) @app.on_event("startup") async def load_model(): global llm # 指定模型路径,并启用张量并行(如果多卡) llm = LLM(model="nanbeige/nanbeige-4.1-3b", tensor_parallel_size=1, gpu_memory_utilization=0.9) @app.post("/generate") async def generate_script(request: GenerationRequest): # 配置采样参数 sampling_params = SamplingParams( temperature=request.temperature, max_tokens=request.max_tokens, stop=["```"] # 设置停止词,当模型输出```时停止,通常用于标记代码块结束 ) # 调用模型生成 outputs = llm.generate([request.prompt], sampling_params) generated_text = outputs[0].outputs[0].text return {"generated_code": generated_text}使用vLLM后,在同样的硬件上,脚本生成的响应时间(Time To First Token)和吞吐量(Tokens per second)都有数量级的提升,非常适合作为后端服务。
实操心得:在初次使用vLLM时,可能会遇到与CUDA版本或PyTorch版本的兼容性问题。一个常见的解决方法是确保你的CUDA、PyTorch和vLLM版本匹配。最稳妥的方式是参照vLLM官方GitHub仓库的Release说明,安装其推荐的PyTorch版本。另外,
gpu_memory_utilization参数可以调整,如果发现显存溢出(OOM),可以适当调低这个值(如0.8)。
3.3 测试框架与浏览器驱动准备
我们生成的脚本最终要能运行,所以必须提前确定好测试框架和浏览器驱动。我们选择Playwright作为浏览器自动化工具,因为它相比Selenium具有更快、更稳定、自动等待等优点,并且自带浏览器内核,无需单独管理WebDriver。
在项目目录下安装Playwright的Python版本:
pip install playwright # 安装Playwright所需的浏览器内核(Chromium, Firefox, WebKit) playwright install这样,我们的环境就具备了执行生成的Python+Playwright测试脚本的能力。
4. 提示词工程:教会AI写测试脚本
这是整个项目中最关键、最需要技巧的部分。大模型本身并不“知道”如何写一个符合我们公司规范的Playwright测试脚本。我们需要通过“提示词”来引导它。提示词的质量直接决定了生成代码的可用性。
4.1 基础提示词模板构建
一个有效的提示词通常包含以下几个部分:
- 角色设定:告诉模型它现在扮演什么角色。
- 任务描述:清晰、具体地说明要它做什么。
- 上下文与约束:提供必要的背景信息、技术栈要求、代码规范等。
- 输出格式:明确要求输出的格式(如:完整的Python代码块)。
- 示例:提供1-2个高质量的输入输出示例,让模型通过示例学习(Few-shot Learning)。
以下是我们经过多次迭代后形成的一个基础提示词模板:
你是一个资深的测试开发工程师,精通使用Python和Playwright进行Web自动化测试。 你的任务是根据用户用自然语言描述的测试场景,生成完整、可直接运行的Playwright测试脚本。 ## 技术要求: 1. 使用Python语言,基于Pytest测试框架和Playwright库。 2. 脚本必须包含必要的导入语句。 3. 使用`playwright.sync_api`的同步API。 4. 元素定位优先使用`get_by_role()`, `get_by_text()`, `get_by_label()`等语义化定位器,其次考虑`get_by_test_id()`,尽量避免使用脆弱的XPath或CSS选择器。 5. 必须包含明确的断言(Assertion)来验证测试结果。 6. 代码结构清晰,包含适当的注释。 7. 将生成的代码放在一个代码块中,以```python开头。 ## 示例: 用户输入:测试登录功能,使用账号admin,密码password123,登录成功后检查页面标题是否包含“仪表盘”。 你输出: ```python import pytest from playwright.sync_api import Page, expect def test_login_success(page: Page): """ 测试用户成功登录 """ # 导航到登录页 page.goto("https://example.com/login") # 填写登录表单 page.get_by_label("用户名或邮箱").fill("admin") page.get_by_label("密码").fill("password123") # 点击登录按钮 page.get_by_role("button", name="登录").click() # 验证登录成功:页面跳转,且标题包含“仪表盘” expect(page).to_have_title(/仪表盘/) # 或者验证某个登录成功后的特定元素出现 # expect(page.get_by_text("欢迎回来,admin!")).to_be_visible()现在,请根据以下用户描述生成测试脚本: 用户描述:{user_input}
在这个模板中,`{user_input}`就是用户提交的自然语言测试用例。我们通过角色、技术要求、示例,极大地约束和引导了模型的输出方向。 ### 4.2 进阶技巧:动态上下文与少样本学习 基础模板能解决大部分简单场景。但对于复杂场景,我们需要更精细的控制。 * **动态上下文**:我们的Web应用可能有不同的环境(测试、预发、生产),登录方式也可能不同。我们可以将这些信息作为“系统上下文”动态注入到提示词中。例如,在用户输入前加上:“当前测试环境基地址为:`https://test.example.com`。所有导航操作请基于此地址。” * **少样本学习**:提供多个不同侧重点的示例,能显著提升模型在复杂情况下的表现。例如,除了登录,我们再提供一个“购物车添加商品”的示例,展示如何处理列表、循环和动态数据。示例2:
用户输入:在商品列表页,将前两个商品加入购物车,然后去购物车页面检查商品数量是否为2。 你输出:
def test_add_to_cart(page: Page): page.goto("https://example.com/products") # 获取所有“加入购物车”按钮,取前两个 add_buttons = page.get_by_role("button", name="加入购物车") for i in range(2): # 操作前两个 add_buttons.nth(i).click() # 可以等待一个短暂的反馈,比如Toast提示 page.wait_for_selector(".toast-success", state="visible", timeout=2000) # 进入购物车页面 page.get_by_role("link", name="购物车").click() # 验证购物车中商品项的数量 cart_items = page.locator(".cart-item") expect(cart_items).to_have_count(2)通过提供2-3个高质量、覆盖不同模式的示例,模型能更好地泛化到新的、未见过的用户描述上。 ### 4.3 处理模糊与边界情况 用户的自然语言描述往往是模糊的。比如:“测试搜索功能,输入关键词后要能看到结果。” 这里有很多未定义项:搜索框在哪里?关键词是什么?如何定义“看到结果”?是结果列表非空,还是第一个结果包含关键词? 我们的策略是: 1. **在提示词中要求明确**:在任务描述里加入:“如果用户描述中存在模糊之处(如未指定具体URL、测试数据、断言细节),请基于常见的Web应用实践进行合理的假设,并在生成的代码中以注释说明你的假设。” 2. **生成后人工审查**:这是必不可少的步骤。AI生成的脚本是“初稿”,测试工程师需要审查这些假设是否合理,并对定位器、断言逻辑进行最终确认和微调。我们不能期望AI一步到位生成完美的、无需修改的脚本,它的价值在于完成80%的模板化、重复性编码工作。 ## 5. 脚本生成、后处理与集成 ### 5.1 完整的生成流程代码示例 结合前面提到的vLLM部署和提示词模板,一个完整的生成端点可能如下所示: ```python # service/generator.py import re from typing import Optional class TestScriptGenerator: def __init__(self, llm_model): self.llm = llm_model self.base_prompt_template = """你是一个资深的测试开发工程师...(此处为上述完整的提示词模板)...用户描述:{user_input}""" def _extract_code_from_response(self, text: str) -> Optional[str]: """从模型返回的文本中提取Python代码块。""" # 匹配 ```python ... ``` 模式 pattern = r"```python\n(.*?)\n```" matches = re.findall(pattern, text, re.DOTALL) if matches: # 返回第一个匹配的代码块 return matches[0].strip() # 如果没有代码块标记,尝试寻找看起来像代码的连续行(备选方案) lines = text.split('\n') code_lines = [] in_code = False for line in lines: if line.strip().startswith('import ') or line.strip().startswith('def ') or line.strip().startswith('from '): in_code = True if in_code: code_lines.append(line) if code_lines: return '\n'.join(code_lines).strip() return None def _post_process_code(self, code: str) -> str: """对提取的代码进行简单的后处理。""" # 1. 确保有必要的import(简单的检查与添加) if "from playwright.sync_api" not in code and "import playwright" not in code: code = "from playwright.sync_api import Page, expect\n" + code if "import pytest" not in code: # 不一定所有测试函数都需要pytest,这里根据情况添加 # 更稳妥的做法是分析代码结构 pass # 2. 移除可能存在的重复或奇怪的空格/注释(这里简化处理) # 可以引入`black`或`autopep8`进行代码格式化,但注意依赖管理 # import subprocess # try: # result = subprocess.run(['black', '--code', code], capture_output=True, text=True, timeout=5) # if result.returncode == 0: # code = result.stdout # except: # pass return code def generate(self, user_input: str, context: dict = None) -> dict: """生成测试脚本的主方法。""" # 1. 构建完整提示词 prompt = self.base_prompt_template.format(user_input=user_input) # 如果有额外上下文(如环境URL),可以在这里插入 if context and context.get('base_url'): prompt = prompt.replace("https://example.com", context['base_url']) # 2. 调用模型 sampling_params = SamplingParams(temperature=0.1, max_tokens=1500, stop=["```"]) outputs = self.llm.generate([prompt], sampling_params) raw_output = outputs[0].outputs[0].text # 3. 提取代码 extracted_code = self._extract_code_from_response(raw_output) if not extracted_code: return { "success": False, "error": "未能从模型响应中提取到有效的代码块。", "raw_output": raw_output } # 4. 后处理 processed_code = self._post_process_code(extracted_code) return { "success": True, "generated_code": processed_code, "raw_output": raw_output # 保留原始输出用于调试 }5.2 生成脚本的验证与试运行
生成的脚本不能直接信任,必须经过验证。我们设计了一个简单的验证流程:
- 语法检查:使用Python的
ast模块解析生成的代码,确保没有语法错误。import ast def validate_syntax(code: str) -> bool: try: ast.parse(code) return True except SyntaxError as e: print(f"语法错误: {e}") return False - 试运行(沙盒环境):这是最直接的验证。我们可以启动一个临期的Playwright浏览器实例,在一个安全的、隔离的测试页面(例如一个静态的Demo页面或公司的测试环境登录页)运行脚本的核心操作部分(跳过涉及具体业务数据的断言)。但这需要谨慎,避免对真实数据造成影响。
- 人工代码审查界面:我们开发了一个简单的Web界面。左侧是用户输入的自然语言描述,中间是AI生成的代码(高亮显示),右侧是一个代码编辑器,允许测试工程师直接修改。界面下方有一个“试运行”按钮,点击后会在后端的一个Docker容器中执行该脚本,并将执行结果(成功、失败、错误信息、截图)返回给前端展示。
5.3 集成到现有工作流
智能脚本生成不是要取代测试工程师,而是作为他们的“超级辅助”。我们将其集成到现有的测试管理平台中:
- 用例管理平台对接:测试人员在用例管理平台(如TestRail, Jira)编写自然语言用例时,可以点击一个“生成自动化脚本”按钮,调用我们的AI服务,将生成的脚本草案附带到该用例下。
- CI/CD流水线:经过人工审查和修正后的、被标记为“稳定”的AI生成脚本,可以像普通脚本一样被测试框架(如Pytest)收集并执行。它们可以成为夜间构建(Nightly Build)回归测试套件的一部分。
- 脚本维护:当页面发生变更导致脚本失败时,测试工程师可以再次利用AI。将旧的脚本和页面变更描述(如“登录按钮的ID从
loginBtn改为了submitLogin”)一起输入,让AI尝试生成修复后的脚本版本,这比手动查找和修改所有相关脚本要高效得多。
6. 效果评估、常见问题与优化方向
6.1 实际效果与局限性
我们在一部分冒烟测试和回归测试用例上进行了实践,大约覆盖了200个左右的用户操作场景。
- 成功率:对于描述清晰、模式常见的场景(如登录、表单提交、列表翻页、详情查看),AI生成脚本的“一次通过率”(生成后无需修改或仅修改定位器即可运行成功)能达到约65%。如果允许测试工程师进行5分钟以内的微调(主要是调整定位器和断言条件),可用率可以提升到90%以上。
- 效率提升:原先手工编写一个中等复杂度的Playwright测试脚本,平均需要15-30分钟。使用AI生成+人工审查修正,平均时间缩短到5-10分钟,效率提升2-3倍。对于简单的脚本,提升更为明显。
- 局限性:
- 复杂交互与状态管理:对于涉及多步骤状态流转、需要操作浏览器本地存储(LocalStorage)、Cookie或处理复杂弹窗、拖拽的场景,AI的表现不稳定,经常生成逻辑错误或缺失步骤的代码。
- 动态数据与断言:AI不擅长处理需要从页面动态提取数据再进行复杂断言的情况。例如,“验证订单总价等于所有商品单价乘以数量之和加上运费”。它可能生成一个硬编码的断言,而不是动态计算的逻辑。
- 非标准UI组件:对于公司自定义的、非常规的UI组件,AI无法理解其交互方式,生成的定位器和操作逻辑往往不正确。
6.2 常见问题与排查技巧
在开发和使用的过程中,我们遇到了不少问题,以下是部分记录:
| 问题现象 | 可能原因 | 排查与解决思路 |
|---|---|---|
| 生成的代码完全跑题,不是测试脚本。 | 提示词不够明确,或用户输入过于简短、模糊。 | 1. 检查并强化提示词中的角色和任务指令。2. 在用户界面引导用户提供更详细的描述,例如通过表单填写“操作步骤”、“预期结果”、“测试数据”。 |
代码语法错误,无法通过ast解析。 | 模型在生成长代码时可能出现“幻觉”,导致括号不匹配、缩进错误或生成无效语法。 | 1. 在提示词中强调“生成语法正确的Python代码”。2. 在后处理阶段加入更强大的代码格式化工具(如black)。3. 降低生成时的temperature参数(如设为0.1),减少随机性。 |
元素定位器总是失败(如用get_by_text(“登录”)但页面上有多个登录按钮)。 | AI基于常见模式生成的定位器不够精确。 | 1. 在提示词中强调使用更精确的定位策略,如get_by_role(button, name=”登录”, exact=True)或get_by_test_id()。2. 这是人工审查阶段必须重点检查的部分。可以训练测试人员使用Playwright的codegen工具录制操作来获取可靠的定位器,再替换AI生成的部分。 |
生成的脚本缺少必要的等待(wait_for_*),导致在慢速网络上失败。 | AI难以判断页面加载和元素出现的具体时机。 | 1. 在提示词中明确要求:“在可能发生页面跳转或元素动态加载的操作后,添加适当的等待,例如page.wait_for_url()或expect(locator).to_be_visible()。”2. 生成的脚本默认采用Playwright的自动等待,但对于某些非标准加载,仍需人工补充。 |
| 模型响应速度慢,或服务出现内存溢出(OOM)。 | 输入提示词过长,或并发请求过多。 | 1. 使用vLLM并开启其PagedAttention和连续批处理(continuous batching)功能。2. 对提示词进行精简,移除不必要的示例或上下文。3. 考虑对模型进行量化(如使用GPTQ、AWQ),在几乎不损失精度的情况下减少显存占用和提升速度。 |
6.3 持续优化方向
这个项目远未结束,还有很大的优化空间:
- 领域微调:收集我们人工修正后的高质量“自然语言-代码”配对数据,对Nanbeige 4.1-3B进行LoRA等方式的微调,让它更熟悉我们公司的页面结构、组件命名和测试规范,从而生成更精准的脚本。
- 工具增强:让AI不仅生成代码,还能调用“工具”。例如,当AI不确定某个按钮的定位器时,它可以“思考”并决定调用一个“元素选择器工具”,该工具可以返回页面上所有按钮的可用定位器列表,供AI选择。这需要构建更复杂的Agent框架。
- 闭环学习:将脚本在CI/CD中的运行结果(成功/失败)以及失败时的错误信息、页面截图反馈给系统。结合这些反馈,系统可以自动分析是定位器问题、等待问题还是逻辑问题,并尝试自动修复或给出修改建议,形成闭环。
- 多模态输入:未来可以结合视觉模型(如GPT-4V),允许测试人员上传页面截图,AI结合截图和文字描述来生成脚本,解决“只可意会不可言传”的UI元素定位问题。
浏览器自动化测试与AI的结合,特别是像Nanbeige 4.1-3B这样的轻量级开源模型的应用,为我们打开了一扇提升测试效率和质量的新大门。它不是一个全自动的替代方案,而是一个强大的“副驾驶”,将测试人员从重复的编码劳动中解放出来,让他们能更专注于测试策略、探索性测试和用户体验等更高价值的工作。从我们的实践来看,这项投资的回报是清晰且显著的。如果你所在的团队也在为自动化测试的编写和维护成本发愁,不妨从这个方向开始做一些探索和尝试。