文 / 测试员周周
上篇回顾【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%(个别使用硬编码索引) 关键洞察:
- Hermes 擅长"形"(代码结构),不擅长"神"(质量意识)
- AI 生成的代码像初级测试工程师写的
- 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()
改进点:
- ✅ 添加显式等待(wait_for_selector)
- ✅ 添加超时设置(timeout=5000)
- ✅ 添加断言验证
- ✅ 添加异常捕获和截图
- ✅ 避免硬编码索引
- ✅ 添加日志输出
改进后评分: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()
改进点:
- ✅ 消除所有固定等待
- ✅ 使用显式等待(wait_for_selector)
- ✅ 使用 ID 选择器(替代 XPath)
- ✅ 添加多重断言
改进后评分: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()
改进点:
- ✅ URL 验证(不应该跳转)
- ✅ 错误消息可见性
- ✅ 错误消息内容验证
- ✅ 登录按钮状态验证
- ✅ 用户名保留验证
改进后评分: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. 如果你不想错过更新,记得点个关注,感谢。