1. 项目概述:当AI大模型遇上浏览器自动化

最近在搞自动化测试的朋友,估计都听过一个词:智能测试生成。这玩意儿听起来挺玄乎,但说白了,就是让AI帮你写测试脚本。我折腾了一段时间,把DeepSeek这个大语言模型和Playwright这个现代浏览器自动化框架给搭到了一起,搞出了一个能用自然语言直接驱动生成测试用例的实战方案。这可不是简单的“AI写代码”,而是一套从需求理解到脚本生成、再到执行验证的完整工作流。

对于测试工程师或者全栈开发者来说,这意味着什么?意味着你不再需要为每一个按钮点击、每一个表单填写去手动编写那些重复的 page.click(‘#submit’) 。你只需要用人类语言描述你想测试的场景,比如“用户登录成功后会跳转到首页”,背后的系统就能理解你的意图,自动生成可执行的Playwright测试代码,甚至能帮你处理一些复杂的断言逻辑。这不仅仅是效率的提升,更是测试思维的一种转变——从“如何实现测试”转向“测试什么”。

DeepSeek作为能力强劲且对开发者友好的大模型,提供了优秀的代码理解和生成能力。而Playwright以其跨浏览器、速度快、API设计优雅的特点,成为了新一代E2E测试的事实标准。两者的结合,正好切中了当前自动化测试领域的一个痛点:脚本编写和维护成本高。通过这个项目,我想分享的不仅仅是如何调用API,更是一套将AI能力真正落地到日常开发测试流水线中的设计思路和实操细节。

2. 核心设计思路与架构拆解

2.1 为什么是DeepSeek + Playwright?

在做技术选型时,我对比过不少方案。先说AI侧,为什么选DeepSeek?首先当然是能力,在代码生成和理解任务上,它的表现相当可靠,尤其是对中文指令的响应很友好,这对于国内团队来说是个加分项。其次,它的API调用成本相对透明,且有不错的免费额度供开发者尝鲜和进行小规模验证,降低了实验门槛。最后,其上下文长度和支持的function calling特性,使得我们可以构建多轮对话,让AI更准确地理解复杂的测试场景。

再看自动化测试框架,为什么是Playwright而不是Selenium或Cypress?这背后有几个关键的考量点。第一是 现代化与性能 。Playwright是为现代Web应用设计的,它直接与浏览器引擎通信,无需WebDriver桥接,速度更快,也更稳定。第二是 强大的自动化能力 。它原生支持多标签页、iframe、文件上传下载、网络拦截与模拟,这些在复杂场景的E2E测试中都是刚需。第三是 出色的选择器引擎和自动等待机制 。Playwright的 text= role= 等选择器非常智能,能写出更健壮、不易因UI微调而失效的脚本;其内置的自动等待几乎消除了手动添加 sleep 的需要。第四是 多语言支持 。虽然我们用Python来粘合整个流程,但Playwright也支持Node.js和Java,这意味着生成的测试脚本能更容易地融入不同的技术栈。

两者的结合点在于:DeepSeek负责将模糊的自然语言需求“翻译”成精确的、结构化的测试意图和操作步骤;Playwright则负责将这些步骤转化为稳定、可执行的浏览器交互代码。我们的系统就是它们之间的“翻译官”和“调度器”。

2.2 系统核心工作流设计

整个系统的核心工作流可以概括为“描述-解析-生成-执行-优化”的闭环。这不是一个单向的代码生成工具,而是一个可以迭代的智能体(Agent)。

第一阶段:需求解析与意图识别。 用户输入一段自然语言,如“测试商品搜索功能,输入‘手机’后,结果列表应该显示相关商品,并且第一个商品可以点击进入详情页”。系统(通过DeepSeek)需要理解这里面的核心实体和操作:“商品搜索框”、“输入‘手机’”、“结果列表”、“第一个商品”、“点击”、“详情页”。同时,它还要识别出断言点:“显示相关商品”(存在性断言)、“可以点击进入详情页”(可交互性与导航断言)。这一步的关键是设计好的提示词(Prompt),引导模型输出结构化的JSON数据,包含操作序列、目标元素描述、预期结果等。

第二阶段:脚本生成与元素定位策略。 拿到结构化的测试意图后,需要生成Playwright代码。这里最大的挑战是 元素选择器 。我们不能让AI凭空编一个 #search-box 的ID,因为实际网站的ID可能千变万化。我的策略是分层处理:

  1. 通用策略优先 :优先使用Playwright推荐的 get_by_role get_by_text get_by_label 等语义化定位方式。例如,“搜索按钮”可以尝试定位为 role=button name 包含“搜索”的元件。这需要AI对ARIA角色有一定了解。
  2. 智能回退 :如果语义化定位失败或不明确,则使用CSS选择器或XPath。这里可以让AI根据元素描述生成“可能”的选择器,但更重要的是,在后续环节引入“选择器验证与推荐”机制。例如,系统可以先用AI生成的选择器尝试定位,如果失败,则利用Playwright的录制工具或开发者工具辅助生成一个更可靠的选择器,并反馈给AI作为学习样本。
  3. 上下文关联 :生成的定位语句不能是孤立的。例如,点击“第一个商品”,代码应该是 page.locator(‘.product-item’).first.click() ,而不是一个写死的索引。这要求AI理解“第一个”这个序数词在Playwright API中的对应表达。

第三阶段:代码执行、验证与自愈。 生成的脚本不会直接扔进CI/CD。我们设计了一个“沙盒执行”环节。系统会自动在一个无头浏览器中运行该脚本,并捕获结果。如果执行失败(如元素未找到、断言失败),系统会将错误日志(包括截图、DOM快照)连同原始需求再次喂给DeepSeek,让它分析失败原因并尝试修复代码。例如,错误是“Timeout 30000ms exceeded”,AI可能会分析出是因为选择器 .btn-submit 不存在,并根据错误页面截图中的按钮文字,将选择器修正为 get_by_role(‘button’, name=‘提交’) 。这个过程可以迭代几次,形成一种简单的“自愈”能力。

第四阶段:脚本优化与模式沉淀。 成功执行的脚本会被保存到用例库。更重要的是,系统会从中提取有效的“操作模式”和“选择器模式”。比如,多个测试用例都成功使用了 page.get_by_role(‘textbox’, name=‘用户名’).fill(‘admin’) 来填写用户名,这个模式就会被标记为“登录用户名输入框的可靠定位方式”。当下次用户再提到“登录”时,系统可以优先推荐或直接复用这个模式,从而越用越准。

注意:这个工作流的关键在于“人机协同”。AI不是万能的,尤其在面对高度定制化、视觉复杂的UI时。我们的设计初衷是让AI承担80%的重复性、模式化编码工作,而工程师则专注于那20%的复杂逻辑校验、数据准备和测试框架的顶层设计。

3. 环境搭建与核心工具链配置

3.1 DeepSeek API接入与初始化

要驱动DeepSeek,首先得搞定API。目前主要使用DeepSeek官方提供的OpenAI兼容接口,这让我们可以用熟悉的 openai 库来调用。

第一步是获取API Key。前往DeepSeek开放平台注册账号并创建应用,就能拿到密钥。这里有个成本控制的小技巧:对于测试生成这种任务,通常不需要使用最高阶的模型。根据我的实测, deepseek-chat 模型在代码生成上的性价比就很高,响应速度和质量都能满足要求。只有在进行非常复杂的逻辑推理或上下文极长时,才需要考虑 deepseek-v4-pro 这类更强大的模型。

安装必要的Python包:

pip install openai playwright

接下来是初始化客户端。我强烈建议将API Key等敏感信息放在环境变量中,而不是硬编码在脚本里。

import os
from openai import OpenAI

# 从环境变量读取API Key
api_key = os.getenv(“DEEPSEEK_API_KEY”)
base_url = “https://api.deepseek.com" # DeepSeek的API端点

client = OpenAI(
    api_key=api_key,
    base_url=base_url
)

# 一个简单的测试调用,检查连接是否正常
def test_connection():
    try:
        response = client.chat.completions.create(
            model=“deepseek-chat”,
            messages=[{“role”: “user”, “content”: “Hello”}],
            max_tokens=10
        )
        print(“API连接成功”)
        return True
    except Exception as e:
        print(f“API连接失败: {e}”)
        return False

对于提示词工程,我创建了一个专门的模块来管理不同任务的提示词模板。这是整个系统的“大脑”所在。

class PromptTemplates:
    @staticmethod
    def test_generation_template(user_scenario: str, page_structure_hint: str = “”) -> str:
        “”“生成Playwright测试脚本的提示词模板”“”
        return f“””
你是一个资深的测试自动化工程师,精通Playwright for Python。
请根据以下用户场景描述,生成一段完整、可执行的Playwright测试代码。

**用户场景描述**:
{user_scenario}

**页面结构提示(可选)**:
{page_structure_hint}

**要求**:
1. 使用Playwright for Python的同步API(`sync_playwright`)。
2. 代码必须包含必要的导入(`from playwright.sync_api import sync_playwright`)。
3. 模拟真实用户操作:合理的等待、使用语义化的定位器(优先使用`get_by_role`, `get_by_text`, `get_by_label`)。
4. 包含明确的断言(assert),验证关键的业务结果。
5. 代码结构清晰,包含测试函数定义(例如`def test_xxx():`),并处理好浏览器的启动和关闭。
6. 为代码添加简要的注释,说明关键步骤。
7. 如果场景中涉及测试数据(如用户名、密码、搜索关键词),请使用明确的示例数据,并在注释中说明。

请只输出最终的Python代码,不要有任何额外的解释。
“””

这个模板明确了角色、任务、技术栈要求和输出格式,能极大地提高AI生成代码的可用性。

3.2 Playwright环境部署与浏览器管理

Playwright的安装比传统Selenium要省心一些,因为它自带浏览器。使用 playwright install 命令可以安装它支持的所有浏览器(Chromium, Firefox, WebKit)。但对于自动化测试生成环境,我通常只安装Chromium,因为它最稳定且性能足够。

# 安装Playwright Python库
pip install playwright
# 安装Chromium浏览器
playwright install chromium

在代码中管理浏览器实例时,有几点需要特别注意:

  1. 上下文(Context)的利用 :不要为每个测试步骤都开启和关闭一个浏览器。应该使用Browser Context。一个Browser实例下可以创建多个独立的Context,每个Context拥有独立的cookie、localStorage等会话状态,且比启动新浏览器轻量得多。这对于生成需要登录状态的测试用例特别有用。
  2. 视口与用户代理 :在创建Context或Page时,最好显式设置视口大小和用户代理,以确保测试环境的一致性,避免响应式布局导致的元素定位问题。
  3. 超时控制 :Playwright的默认超时可能不适合所有场景。我习惯在全局或Page级别设置一个合理的超时,比如 page.set_default_timeout(30000)

下面是一个健壮的浏览器管理上下文管理器示例:

from playwright.sync_api import sync_playwright

class BrowserManager:
    def __init__(self, headless: bool = True):
        self.headless = headless
        self.playwright = None
        self.browser = None

    def __enter__(self):
        self.playwright = sync_playwright().start()
        # 启动Chromium,可配置其他参数如慢速模拟 `slow_mo=1000`
        self.browser = self.playwright.chromium.launch(headless=self.headless)
        return self.browser

    def __exit__(self, exc_type, exc_val, exc_tb):
        if self.browser:
            self.browser.close()
        if self.playwright:
            self.playwright.stop()

# 使用示例
with BrowserManager(headless=False) as browser:
    context = browser.new_context(
        viewport={‘width’: 1920, ‘height’: 1080},
        user_agent=‘Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36’
    )
    page = context.new_page()
    # ... 执行生成的测试代码 ...

实操心得:将浏览器管理封装成资源管理器模式,可以确保即使在生成的测试代码执行出错时,浏览器也能被正确关闭,避免资源泄漏。这对于长时间运行的自动化服务至关重要。

4. 自然语言到测试脚本的转换引擎实现

4.1 结构化提示词设计与多轮对话

让AI一次性生成完美的测试脚本是理想状态,但现实往往需要“沟通”。因此,我设计了一个多轮对话的机制。第一轮,AI根据基础模板生成初版脚本。如果执行失败或用户不满意,我们可以将错误信息或反馈作为后续对话的输入,让AI进行修正。

核心的 TestGenerator 类需要维护一个对话历史( message_history )。每次调用都不仅仅是发送当前指令,而是附带上文,让AI理解我们正在“协作”完成什么任务。

class TestGenerator:
    def __init__(self, client):
        self.client = client
        self.message_history = [] # 维护对话历史

    def generate_initial_script(self, scenario: str) -> str:
        “”“第一轮:根据场景生成初始脚本”“”
        system_prompt = “你是一个Playwright测试代码生成专家。请生成准确、健壮、可执行的代码。”
        user_prompt = PromptTemplates.test_generation_template(scenario)

        self.message_history = [
            {“role”: “system”, “content”: system_prompt},
            {“role”: “user”, “content”: user_prompt}
        ]

        response = self.client.chat.completions.create(
            model=“deepseek-chat”,
            messages=self.message_history,
            temperature=0.2, # 温度设低,让输出更确定、更偏向代码
            max_tokens=2000
        )
        generated_code = response.choices[0].message.content
        # 将AI的回复也加入历史,为后续对话做准备
        self.message_history.append({“role”: “assistant”, “content”: generated_code})
        return self._extract_code(generated_code)

    def refine_script(self, previous_code: str, error_feedback: str) -> str:
        “”“第二轮及以后:根据错误反馈修正脚本”“”
        refinement_prompt = f“””
之前生成的Playwright代码在执行时遇到了问题。
这是之前的代码:
```python
{previous_code}

执行错误或反馈如下: {error_feedback}

请分析错误原因,并修正代码。修正后的代码需要能解决上述问题。 同样,只输出修正后的完整Python代码。 “”” self.message_history.append({“role”: “user”, “content”: refinement_prompt})

    response = self.client.chat.completions.create(
        model=“deepseek-chat”,
        messages=self.message_history,
        temperature=0.2,
        max_tokens=2000
    )
    refined_code = response.choices[0].message.content
    self.message_history.append({“role”: “assistant”, “content”: refined_code})
    return self._extract_code(refined_code)

def _extract_code(self, raw_response: str) -> str:
    “”“从AI的回复中提取纯净的Python代码块。”“”
    import re
    # 尝试匹配 ```python ... ``` 代码块
    code_block_match = re.search(r’```python\n(.*?)\n```’, raw_response, re.DOTALL)
    if code_block_match:
        return code_block_match.group(1).strip()
    # 如果没有代码块标记,假设整个回复就是代码(但这种情况较少)
    return raw_response.strip()

`temperature`参数在这里很关键。生成代码时,我通常设置为0.1-0.3,以降低随机性,让输出更稳定、更符合预期。只有在需要AI“创造性”地提出多种测试方案时,才会调高这个值。

### 4.2 代码生成、安全执行与结果捕获

生成代码只是第一步,如何安全地执行这段可能包含错误的、动态生成的代码,才是真正的挑战。直接使用`exec()`是危险且不推荐的。我采用的方法是:将生成的代码写入一个临时Python文件,然后使用`subprocess`模块在独立的进程中运行它。这样做的好处是隔离性好,即使生成的代码有无限循环或致命错误,也不会搞垮主进程,并且能方便地捕获标准输出、标准错误和退出码。

```python
import tempfile
import subprocess
import os
import sys

class ScriptExecutor:
    @staticmethod
    def execute_generated_code(code: str, test_name: str = “generated_test”) -> dict:
        “”“
        在独立进程中执行生成的代码。
        返回包含执行结果、输出、错误和持续时间的字典。
        ”“”
        result = {“success”: False, “output”: “”, “error”: “”, “duration”: 0.0}

        # 创建临时文件
        with tempfile.NamedTemporaryFile(mode=‘w’, suffix=‘.py’, delete=False) as f:
            # 为临时文件添加必要的导入和测试包装(如果需要)
            full_code = f“””
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).parent))

from playwright.sync_api import sync_playwright
import traceback

{code}

if __name__ == ‘__main__’:
    try:
        # 如果生成的代码是函数,这里可以尝试调用它。
        # 更通用的做法是,要求AI生成的代码本身就是可执行的脚本片段。
        exec(open(__file__).read())
        print(“[EXECUTOR] Test execution finished without explicit assertion errors.”)
    except AssertionError as e:
        print(f“[EXECUTOR] Assertion failed: {e}”)
        sys.exit(1)
    except Exception as e:
        print(f“[EXECUTOR] Unexpected error: {e}”)
        traceback.print_exc()
        sys.exit(2)
“””
            f.write(full_code)
            temp_file_path = f.name

        try:
            # 使用当前Python解释器执行临时文件
            start_time = time.time()
            process = subprocess.run(
                [sys.executable, temp_file_path],
                capture_output=True,
                text=True,
                timeout=60, # 设置超时,防止死循环
                cwd=os.path.dirname(temp_file_path)
            )
            end_time = time.time()
            result[“duration”] = end_time - start_time
            result[“output”] = process.stdout
            result[“error”] = process.stderr

            # 判断是否成功:退出码为0,且标准错误中没有特定的Playwright启动错误
            if process.returncode == 0:
                result[“success”] = True
            else:
                # 即使有退出码,也可能只是断言失败,这属于“测试失败”而非“执行错误”
                # 我们可以根据错误信息进一步分类
                if “AssertionError” in process.stderr:
                    result[“error_type”] = “AssertionFailed”
                else:
                    result[“error_type”] = “ExecutionError”
                result[“success”] = False

        except subprocess.TimeoutExpired:
            result[“error”] = “Test execution timed out after 60 seconds.”
            result[“error_type”] = “Timeout”
        except Exception as e:
            result[“error”] = str(e)
            result[“error_type”] = “SystemError”
        finally:
            # 清理临时文件
            os.unlink(temp_file_path)

        return result

这个执行器提供了基本的隔离和超时控制。返回的 result 字典包含了丰富的诊断信息,可以用于后续的失败分析和AI修正。

4.3 元素定位策略的增强与验证

AI生成的选择器可能不准确。为了提高成功率,我引入了“选择器验证与增强”环节。思路是:在AI生成代码后、正式执行前(或首次执行失败后),尝试用Playwright的API去验证那些关键的选择器是否能在目标页面上唯一匹配到元素。

我们可以设计一个函数,接收AI生成的选择器字符串和页面URL(或Page对象),返回验证结果和建议。

from playwright.sync_api import sync_playwright

class SelectorValidator:
    @staticmethod
    def validate_and_suggest(selector: str, page_url: str) -> dict:
        “”“
        验证选择器,并尝试提供改进建议。
        :param selector: AI生成的选择器字符串,如 “button:has-text(‘Submit’)”
        :param page_url: 要测试的页面URL
        :return: 包含验证结果、匹配数量、建议选择器等信息的字典
        ”“”
        result = {“original”: selector, “is_valid”: False, “match_count”: 0, “suggestions”: []}
        with sync_playwright() as p:
            browser = p.chromium.launch(headless=True)
            context = browser.new_context()
            page = context.new_page()
            try:
                page.goto(page_url, wait_until=“networkidle”)
                # 尝试使用选择器定位
                elements = page.locator(selector).all()
                result[“match_count”] = len(elements)
                result[“is_valid”] = len(elements) > 0

                if len(elements) == 0:
                    # 如果没找到,尝试用Playwright的录制功能生成一个选择器(这里简化,实际可调用codegen)
                    # 或者,我们可以让AI根据页面HTML片段重新生成选择器
                    result[“suggestions”].append(“选择器未匹配到任何元素。建议检查元素是否存在或选择器语法。”)
                elif len(elements) > 1:
                    result[“suggestions”].append(f“选择器匹配到{len(elements)}个元素,可能不够精确。尝试使用更特定的属性,如‘data-testid’。”)
                else:
                    # 如果唯一匹配,可以进一步获取元素的推荐选择器
                    recommended = page.evaluate(““”(selector) => {
                        const el = document.querySelector(selector);
                        if (!el) return [];
                        const suggestions = [];
                        // 优先推荐data-testid
                        if (el.dataset.testid) suggestions.push(`[data-testid=“${el.dataset.testid}”]`);
                        // 推荐ID
                        if (el.id) suggestions.push(`#${el.id}`);
                        // 推荐有唯一文本的文本选择器
                        if (el.innerText && el.innerText.trim()) suggestions.push(`text=“${el.innerText.trim()}”`);
                        return suggestions;
                    }““”, selector)
                    result[“suggestions”].extend(recommended)

            except Exception as e:
                result[“error”] = str(e)
                result[“is_valid”] = False
            finally:
                browser.close()
        return result

这个验证器的结果可以反馈给AI。例如,如果AI生成了 #loginBtn 但验证发现匹配数为0,我们可以将错误信息“选择器#loginBtn未找到任何元素,当前页面按钮的ID可能是‘submit-login’”连同页面关键HTML片段一起发给AI,要求它修正。通过几次这样的交互,AI能学习到目标网站的实际DOM结构,生成的选择器会越来越准。

5. 实战:构建端到端的智能测试生成流水线

5.1 从需求描述到可执行用例的全流程

让我们用一个完整的例子串起所有环节。假设我们要测试一个简易的电商网站搜索功能。

第一步:用户输入自然语言需求。

“在电商首页的搜索框输入‘蓝牙耳机’,点击搜索按钮,验证结果页面标题包含‘蓝牙耳机’,并且至少显示一条商品结果。”

第二步:系统调用AI生成初始脚本。 TestGenerator 使用预设的提示词模板,将上述需求发送给DeepSeek。AI可能会返回如下代码:

from playwright.sync_api import sync_playwright, expect

def test_search_bluetooth_headphones():
    with sync_playwright() as p:
        browser = p.chromium.launch(headless=False)
        context = browser.new_context()
        page = context.new_page()

        # 1. 导航至电商首页
        page.goto(“https://demo.ecommerce.com”)

        # 2. 定位搜索框并输入关键词
        search_box = page.get_by_role(“textbox”, name=“搜索商品”)
        search_box.fill(“蓝牙耳机”)

        # 3. 点击搜索按钮
        search_button = page.get_by_role(“button”, name=“搜索”)
        search_button.click()

        # 4. 等待结果页面加载并验证标题
        page.wait_for_url(“**/search**”) # 假设搜索后URL会变化
        expect(page).to_have_title(“蓝牙耳机 - 搜索结果”)

        # 5. 验证至少有一条商品结果
        product_items = page.locator(“.product-item”).all()
        assert len(product_items) > 0, “搜索结果页面未显示任何商品”

        browser.close()

第三步:选择器验证与页面探测。 在实际执行前, SelectorValidator 会对关键选择器进行预验证,比如 .product-item 。如果验证发现这个类名不存在,或者匹配数量为0,系统可以自动访问目标网站,抓取搜索结果页面的部分HTML结构(例如,获取所有具有 class 属性的div/li元素列表),然后将这个结构信息作为“页面结构提示”反馈给AI,要求它重新生成更准确的选择器。

第四步:安全执行与结果捕获。 ScriptExecutor 将修正后的代码在临时环境中运行。假设网站的真实商品列表项CSS类是 .product-card ,而AI最初生成的是 .product-item ,那么执行会失败(断言错误)。执行器会捕获到 AssertionError: 搜索结果页面未显示任何商品 以及可能的 TimeoutError (如果因为元素找不到导致后续操作卡住)。

第五步:失败分析与脚本修正。 系统将失败的代码、错误日志以及从实际页面探测到的信息(如“页面中存在.product-card元素”)打包,发送给DeepSeek进行第二轮修正。AI在收到这些反馈后,可能会将选择器修正为 .product-card ,并可能调整等待逻辑。

第六步:生成最终脚本与报告。 经过1-2轮修正,脚本成功执行。系统将最终可用的脚本保存到用例库,并生成一份简单的执行报告,包括总耗时、通过/失败状态、以及过程中发现的问题(如选择器不匹配)。

5.2 集成到CI/CD与测试管理平台

生成的脚本不能是孤立的。为了发挥最大价值,需要将其集成到现有的开发流程中。

  1. 格式化与标准化 :生成的脚本需要符合团队的代码规范(如PEP 8)。可以使用 black isort 等工具在保存前自动格式化。同时,将生成的测试函数封装到标准的测试框架(如 pytest )中,使其能够被 pytest 发现和执行。

    # 在生成代码后,可以自动添加pytest装饰器或放入特定模块
    import pytest
    @pytest.mark.e2e
    def test_search_bluetooth_headphones():
        # ... AI生成的代码 ...
    
  2. 与测试管理工具集成 :可以将生成的测试用例与TestRail、Xray或Allure等测试管理工具关联。为每个生成的用例添加唯一的标识符和描述,执行结果可以自动回传到这些平台,形成可视化的测试报告。

  3. CI/CD流水线触发 :在GitLab CI、Jenkins或GitHub Actions中配置任务,定期(如每夜)或基于事件(如合并请求)触发智能测试生成流程。流程可以是:拉取最新代码 -> 启动测试生成服务针对核心功能点生成用例 -> 执行生成的用例 -> 发布测试报告。对于失败的用例,报告可以关联到具体的AI生成日志和页面截图,方便排查是需求描述问题、AI理解问题还是真实的产品缺陷。

  4. 用例库管理与去重 :随着时间推移,会积累大量生成的用例。需要建立简单的用例库管理系统,对用例进行去重(基于操作步骤和断言点的哈希值)、版本管理和有效性标记(标记因UI改版而失效的用例)。当再次收到类似的需求描述时,系统可以先在用例库中检索是否有可复用的现有脚本,提高效率并保持一致性。

6. 常见问题、挑战与优化策略

在实际落地过程中,会遇到各种各样的问题。下面是我总结的一些典型挑战和应对策略。

6.1 AI生成代码的典型问题与调试

问题现象 可能原因 排查与解决策略
元素定位失败 选择器语法错误、元素属性动态变化、页面未加载完成、iframe或Shadow DOM。 1. 语法检查 :用 SelectorValidator 预验证。2. 增加等待 :在操作前添加 page.wait_for_selector() page.wait_for_function() 。3. 使用更稳定的定位器 :引导AI优先使用 data-testid 等测试专用属性,或 get_by_role get_by_text 。4. 处理动态内容 :如果ID或类名是动态的,让AI使用XPath部分匹配( contains )或CSS属性选择器( [class*=”partial-name”] )。
断言失败 预期状态判断不准、异步操作未完成、数据不一致。 1. 使用Playwright的断言 :引导AI使用 expect(locator).to_have_text() 而非简单的 assert page.text_content() == … ,前者自带重试机制。2. 明确等待条件 :在断言前明确等待某个特定状态出现,如网络请求完成、元素可见等。3. 软化断言 :对于列表数量等,使用 assert len(items) >= 1 而非 == 5
脚本逻辑错误 AI误解了操作顺序、遗漏了前置步骤(如登录)、生成了不存在的API调用。 1. 分步生成与验证 :对于复杂场景,拆分成多个子步骤,让AI分步生成并验证每一步。2. 提供上下文 :在提示词中明确提供前置条件,如“假设用户已登录”。3. 代码语法检查 :使用 ast 模块或 pyflakes 对生成的代码进行快速语法检查,捕获明显的API错误。
执行超时 死循环、等待条件永不满足、网络问题。 1. 设置全局超时 :在 ScriptExecutor 中严格限制子进程执行时间。2. 优化等待策略 :避免使用固定的 page.wait_for_timeout() ,改用事件驱动的等待。3. 超时后截图 :在超时前让脚本保存页面截图和HTML快照,供后续分析。

6.2 提示词工程的优化技巧

提示词的质量直接决定生成代码的质量。经过大量实践,我总结出几个有效的优化方向:

  1. 提供范例(Few-Shot Learning) :在提示词中直接给出一两个高质量的例子,比单纯描述规则有效得多。例如,在系统提示词后附上一个“登录测试”的完整代码示例,AI会模仿其风格和结构。
  2. 约束输出格式 :明确要求“只输出代码”、“代码必须包含在 python 块中”,这能极大减少AI返回多余的解释性文字,方便后续解析。
  3. 分解复杂任务 :对于“测试购物车全流程”这种复杂场景,不要指望AI一次生成上百行完美代码。可以拆解:“第一步,生成将商品加入购物车的测试”、“第二步,生成在购物车中修改数量的测试”、“第三步,生成结算流程的测试”。然后将多个生成的函数组合起来。
  4. 利用Function Calling(如果模型支持) :如果使用的DeepSeek模型版本支持Function Calling,可以定义好“生成测试步骤”、“定位元素”、“添加断言”等几个函数,让AI以结构化JSON的形式输出测试计划,再由我们的系统将其转换为Playwright代码。这样可控性更强。
  5. 持续迭代提示词 :建立一个提示词版本库。每次生成失败或成功,都分析原因。如果是提示词不清晰导致的问题,就修正提示词。这是一个持续优化的过程。

6.3 维护性与扩展性考量

这个系统本身也需要维护。随着被测应用(AUT)的更新,UI会变,选择器会失效。如何让系统适应这种变化?

  1. 建立元素选择器知识库 :维护一个映射表,将业务概念(如“登录按钮”、“搜索框”)映射到当前最有效的定位策略(如 data-testid=“login-submit” )。AI生成代码时,先查询这个知识库。知识库可以手动维护,也可以通过定期运行“选择器健康度扫描”脚本自动更新。
  2. 实现测试脚本的自动更新 :当UI发生重大变更导致一批用例失败时,可以触发一个批量修复流程。将失败的用例和新的页面快照(或变更描述)批量提交给AI,请求其进行批量修正。
  3. 支持多应用与多版本 :系统架构应该支持配置多个被测应用(不同的URL、不同的登录方式、不同的页面结构)。可以为每个应用维护独立的提示词库和元素知识库。
  4. 人的审核环节必不可少 :在关键路径上,尤其是生成的脚本第一次被加入CI/CD流水线前,应该有人工审核环节。审核者可以检查脚本的逻辑是否正确、断言是否完备、是否有安全隐患(如是否包含了硬编码的敏感信息)。AI是副驾驶,方向盘最终还得在人手里。

智能测试生成不是要取代测试工程师,而是将他们从重复的、机械的编码劳动中解放出来,让他们能更专注于测试策略设计、复杂业务场景探索和用户体验评估这些更高价值的工作。通过DeepSeek和Playwright的结合,我们正在向这个目标迈出坚实的一步。这个方案目前已经在一些相对标准化的Web应用测试中取得了不错的效果,对于快速覆盖核心场景的冒烟测试和回归测试尤其有用。当然,面对极度动态、高度定制化的前端应用,还有很长的路要走,但每一次迭代,都让机器更懂我们的测试意图。

Logo

这里是“一人公司”的成长家园。我们提供从产品曝光、技术变现到法律财税的全栈内容,并连接云服务、办公空间等稀缺资源,助你专注创造,无忧运营。

更多推荐