[Hermes系列10]Hermes 生成代码质量提升指南:从 70 分到 90 分的 5 个技巧

0 阅读8分钟

文 / 测试员周周

上篇回顾【Hermes系列8】Hermes 生成的测试代码能直接用吗?我 Review 了 10 个脚本(附真实评测数据) - 掘金核心数据:平均分 70.9,20% 可直接用,40% 需小幅修改,40% 需大幅重写

01上篇回顾

上篇我们评测了 10 个 Hermes 生成的测试脚本,核心发现:

评分结果

  • 平均分:70.9/100

  • 最高分:87 分(04-test_dashboard_load.py)

  • 最低分:50 分(07-test_delete_product.py) 问题分布

  • 代码结构:61%(缺少文档、硬编码)

  • 异常处理:31%(缺少超时、没有截图)

  • 断言问题:7%(断言太弱、覆盖不足)

  • 定位器问题:1%(个别使用硬编码索引) 关键洞察

  1. Hermes 擅长"形"(代码结构),不擅长"神"(质量意识)
  2. AI 生成的代码像初级测试工程师写的
  3. Prompt 质量决定代码质量上限

但这篇文章不讲问题,只讲解决方案。

我会用 3 个改进实战 +4 个 Prompt 技巧,教你如何把 Hermes 生成的代码从 70 分提升到 90 分。

02 改进实战 1:补充异常处理(50 分 → 85 分)

案例:07-test_delete_product.py(原评分 50 分)

原代码

def test_delete():
    with sync_playwright() as p:
        browser = p.chromium.launch()
        page = browser.new_page()
        
        page.goto("http://localhost:5000/login")
        page.fill("#username", "admin")
        page.fill("#password", "123456")
        page.click("#login-btn")
        
        page.wait_for_timeout(2000)
        page.click("#nav-products")
        
        # 删除第一个商品(硬编码索引)
        page.click(".delete-btn:nth-child(1)")
        
        page.wait_for_timeout(1000)
        
        browser.close()

问题清单

  • ❌ 没有断言(-20 分)
  • ❌ 使用硬编码索引(-5 分)
  • ❌ 使用固定等待(-5 分)
  • ❌ 缺少超时设置(-5 分)
  • ❌ 没有异常捕获(-3 分)
  • ❌ 失败时没有截图(-3 分)

改进后代码

def test_delete_product():
    """测试删除商品功能"""
    with sync_playwright() as p:
        browser = p.chromium.launch(headless=True)
        page = browser.new_page()
        
        try:
            # 登录
            page.goto("http://localhost:5000/login", timeout=10000)
            page.fill("#username", "admin")
            page.fill("#password", "123456")
            page.click("#login-btn")
            page.wait_for_url("/dashboard", timeout=5000)
            
            # 访问商品页面
            page.click("#nav-products")
            page.wait_for_selector("#products-table", timeout=5000)
            
            # 获取第一个商品的 ID(避免硬编码索引)
            delete_btn = page.query_selector(".delete-btn")
            if not delete_btn:
                print("⚠️ 没有可删除的商品")
                return
            
            product_id = delete_btn.get_attribute("data-id")
            print(f"准备删除商品:{product_id}")
            
            # 删除商品
            delete_btn.click()
            page.wait_for_selector(f".delete-btn[data-id='{product_id}']", state="detached", timeout=5000)
            
            # 验证删除成功
            assert product_id not in page.content(), "商品未成功删除"
            print("✅ 商品删除成功")
            
        except Exception as e:
            # 失败时截图
            screenshot_path = f"screenshots/delete_failed_{datetime.now().strftime('%Y%m%d_%H%M%S')}.png"
            page.screenshot(path=screenshot_path)
            print(f"❌ 测试失败,截图已保存:{screenshot_path}")
            raise
        finally:
            browser.close()

改进点

  1. ✅ 添加显式等待(wait_for_selector)
  2. ✅ 添加超时设置(timeout=5000)
  3. ✅ 添加断言验证
  4. ✅ 添加异常捕获和截图
  5. ✅ 避免硬编码索引
  6. ✅ 添加日志输出

改进后评分:85 分(+35 分)

03 改进实战 2:优化等待策略(消除固定等待)

案例:05-test_products_page_load.py(原评分 65 分)

原代码问题

# ❌ 问题 1:固定等待 2 秒
page.wait_for_timeout(2000)
page.click("/html/body/div[1]/nav/a[1]")

# ❌ 问题 2:使用 XPath 硬编码
page.click("/html/body/div[1]/nav/a[1]")

# ❌ 问题 3:只有一个断言
assert "商品" in page.title()

改进后代码

def test_products_page_load():
    """测试商品页面加载"""
    with sync_playwright() as p:
        browser = p.chromium.launch(headless=True)
        page = browser.new_page()
        
        # 登录
        page.goto("http://localhost:5000/login", timeout=10000)
        page.fill("#username", "admin")
        page.fill("#password", "123456")
        page.click("#login-btn")
        page.wait_for_url("/dashboard", timeout=5000)
        
        # 使用 ID 选择器访问商品页面(替代 XPath)
        page.click("#nav-products")
        
        # 显式等待页面元素加载
        page.wait_for_selector("#products-table", timeout=5000)
        page.wait_for_selector("#add-product-form", timeout=5000)
        
        # 多重断言验证
        assert "/products" in page.url, "URL 不正确"
        assert "商品管理" in page.title(), "页面标题不正确"
        assert page.is_visible("#products-table"), "商品表格未显示"
        assert page.is_visible("#add-product-btn"), "添加按钮未显示"
        
        print("✅ 商品页面加载测试通过")
        
        browser.close()

改进点

  1. ✅ 消除所有固定等待
  2. ✅ 使用显式等待(wait_for_selector)
  3. ✅ 使用 ID 选择器(替代 XPath)
  4. ✅ 添加多重断言

改进后评分:87 分(+22 分)

04 改进实战 3:强化断言(从 1 个到 5 个)

案例:02-test_login_wrong_password.py(原评分 65 分)

原代码

def test_login_wrong_password():
    with sync_playwright() as p:
        browser = p.chromium.launch()
        page = browser.new_page()
        page.goto("http://localhost:5000/login")
        
        page.fill("#username", "admin")
        page.fill("#password", "wrongpassword")
        page.click("#login-btn")
        
        page.wait_for_timeout(1000)
        
        # ❌ 只有一个弱断言
        assert "错误" in page.content()
        
        browser.close()

改进后代码

def test_login_wrong_password():
    """测试密码错误时的登录失败场景"""
    with sync_playwright() as p:
        browser = p.chromium.launch(headless=True)
        page = browser.new_page()
        
        try:
            # 访问登录页
            page.goto("http://localhost:5000/login", timeout=10000)
            
            # 填写错误的密码
            page.fill("#username", "admin")
            page.fill("#password", "wrongpassword")
            page.click("#login-btn")
            
            # 等待错误消息显示
            page.wait_for_selector("#error-message", timeout=5000)
            
            # 5 个断言验证
            assert page.url == "http://localhost:5000/login", "URL 不应该跳转"
            assert page.is_visible("#error-message"), "错误消息未显示"
            assert "错误" in page.text_content("#error-message"), "错误消息内容不正确"
            assert page.is_enabled("#login-btn"), "登录按钮应该仍然可用"
            assert page.input_value("#username") == "admin", "用户名应该保留"
            
            print("✅ 密码错误登录测试通过")
            
        except Exception as e:
            page.screenshot(path="screenshots/login_wrong_password_failed.png")
            raise
        finally:
            browser.close()

改进点

  1. ✅ URL 验证(不应该跳转)
  2. ✅ 错误消息可见性
  3. ✅ 错误消息内容验证
  4. ✅ 登录按钮状态验证
  5. ✅ 用户名保留验证

改进后评分:88 分(+23 分)

05 Prompt 技巧:4 个让 Hermes 生成更好代码的方法

基于本次评测的对比实验,我总结了 4 个 Prompt 技巧:

技巧 1:给更详细的上下文

# ❌ 简单提示(得分 65)
"写一个登录测试"

# ✅ 详细提示(得分 85)
"""
写一个登录测试脚本,要求:

【技术栈】
- Playwright + Python (sync_api)
- headless 模式运行

【测试场景】
1. 正常登录(admin/123456)→ 跳转到 /dashboard
2. 密码错误 → 显示"密码错误"
3. 空用户名 → 显示"请输入用户名"

【代码要求】
- 使用 ID 选择器优先
- 添加显式等待(timeout=5000)
- 每个场景至少 3 个断言
- 失败时自动截图
- 添加文档字符串和注释
"""

技巧 2:指定编码规范

# ✅ 指定规范
"""
代码要求:
1. 函数命名:test_前缀 + snake_case
2. 每个函数添加文档字符串(说明测试目的)
3. 使用 ID 选择器优先,避免 XPath
4. 所有操作添加 timeout=5000
5. 测试数据用常量定义在文件开头
6. 添加 try-except 异常处理
7. 失败时截图并记录日志
"""

技巧 3:提供示例代码

# ✅ 提供示例
"""
参考以下代码风格:

def login_success():
    '''测试正常登录场景'''
    with sync_playwright() as p:
        browser = p.chromium.launch(headless=True)
        page = browser.new_page()
        
        try:
            page.goto("http://localhost:5000/login", timeout=10000)
            page.fill("#username", "admin")
            page.fill("#password", "123456")
            page.click("#login-btn")
            page.wait_for_url("/dashboard", timeout=5000)
            
            assert page.url == "/dashboard"
            assert "欢迎" in page.content()
            
        except Exception as e:
            page.screenshot(path="screenshots/login_failed.png")
            raise
        finally:
            browser.close()

请按照这个风格写"密码错误登录"测试...
"""

技巧 4:迭代优化

# 第 1 轮:生成初版
"写一个登录测试,使用 Playwright"

# 第 2 轮:优化定位器
"把所有选择器改成 ID 选择器,避免使用 XPath"

# 第 3 轮:添加等待
"添加显式等待(wait_for_selector),不要用固定等待"

# 第 4 轮:强化断言
"给每个场景添加至少 3 个断言,覆盖 URL、元素、内容"

# 第 5 轮:添加异常处理
"添加 try-except,失败时自动截图"

06 迭代优化演示

完整对话记录(以登录测试为例):

第 1 轮:生成初版(得分 65)

我:写一个登录测试
Hermes: [生成代码]

第 2 轮:优化定位器(得分 72)

我:把所有选择器改成 ID 选择器,避免使用 XPath
Hermes: [修改代码]

第 3 轮:添加等待(得分 78)

我:添加显式等待(wait_for_selector),不要用固定等待
Hermes: [修改代码]

第 4 轮:强化断言(得分 85)

我:给每个场景添加至少 3 个断言
Hermes: [修改代码]

第 5 轮:添加异常处理(得分 90)

我:添加 try-except,失败时自动截图
Hermes: [修改代码]

关键:不要期望一次生成完美代码,要像 Code Review 一样逐步指导。

08 总结与建议

核心观点

1. Hermes 生成的代码平均 71 分,可以用作初版,但必须人工 Review
2. 20% 可直接用(简单场景),40% 需小幅修改40% 需大幅重写
3. 改进的关键:异常处理、等待策略、断言强化
4. Prompt 质量决定上限,越详细越好
5. 迭代优化是最有效的方法

上篇回顾【Hermes系列8】Hermes 生成的测试代码能直接用吗?我 Review 了 10 个脚本(附真实评测数据) - 掘金

下一篇:评测相关、Hermes 系列、crewAI 系列都有可能,因为我要求自己一定要真实实战,所以哪个先有效果就先分享哪篇;**

P.S. 如果你不想错过更新,记得点个关注,感谢。