近期測試圈有一個爆火的AI小團體,它就是Playwright 的團隊研發(fā)的3個AI小助手,名字挺唬人:Planner、Generator、Healer。
![]()
但說白了,就是三個干臟活累活的“小弟”:
- Planner:打開你的應(yīng)用,到處點點看看,輸出一份測試計劃(Markdown);
- Generator:把測試計劃翻譯成 .spec.ts 測試代碼;
- Healer:跑失敗的測試,嘗試自己修。
它們統(tǒng)稱為:Playwright Test Agents ,就是 Playwright 框架在原生版本集成的三款 AI 助手,主要用來解決自動化測試的核心難題:幫你“想”(Planner)、幫你“寫”(Generator)、再幫你“修”(Healer)。
今天咱們從一個實際經(jīng)歷出發(fā),看看他實操下來到底順不順利,碰到哪些麻煩,怎么搞定的,最后學(xué)到了啥。
項目背景
公司有個內(nèi)部數(shù)據(jù)中臺,因為開發(fā)換了好幾撥,文檔幾乎等于沒有,公司最近規(guī)范文檔,需要把核心流程(登錄 → 數(shù)據(jù)源配置 → 創(chuàng)建數(shù)據(jù)集 → 發(fā)布 API)的 E2E 測試補上。
拿行內(nèi)的話說,這簡直就是一個“屎山”項目。
實踐過程分享
第一步:Seed 測試
操作步驟:
官方文檔說,先寫一個 seed.spec.ts,用來做環(huán)境初始化和前置驗證。
因為項目里需要先登錄,登錄之后還要等幾個異步權(quán)限加載完成才能進(jìn)到主頁。
所以一開始寫得很簡單:
test('seed', async ({ page }) => { await page.goto('https://xxx.com/login'); await page.fill('#username', 'myuser'); await page.fill('#password', 'mypass'); await page.click('button:has-text("登錄")'); await page.waitForURL('**/dashboard');});
跑一下,通過。然后開始執(zhí)行 npx playwright init-agents --loop=vscode,初始化 Agent。
結(jié)果展示:
結(jié)果 Planner 開始探索時,直接在登錄頁卡住。
因為 Seed 里沒有把登錄態(tài)保存下來,Planner 每次啟動都會重新走一遍 seed 流程,但不知道哪里沒處理好,總是登錄失敗。
原因分析:
Planner 在探索的時候,會重新運行 seed 測試中的每一步,但它是通過 MCP 工具來操作瀏覽器的,和本地手動跑 test 的環(huán)境不一樣。比如項目的登錄接口有 CSRF token,seed 測試?yán)镉昧?page.context() 的 cookie 復(fù)用,但 MCP 工具沒有自動帶上。
重試過程:Seed 測試不能只保證“能跑通”,還要保證能夠被 Agent 正確重放。最好的實踐是:Seed 里只做最簡單的頁面打開和基本元素檢查,把登錄和認(rèn)證放到 自定義 fixture 里,然后在 playwright.config.ts 里配置 storageState。
改成如下:
// fixtures.tsimport { test as base } from '@playwright/test';export const test = base.extend({ authenticatedPage: async ({ page }, use) => { await page.goto('/login'); // 登錄邏輯 await page.context().storageState({ path: 'auth.json' }); await use(page); },});
然后在 seed 里直接 test.use({ storageState: 'auth.json' })。這樣 Planner 就不會每次都被登錄流程拖累了。
經(jīng)驗總結(jié):Seed 測試是為 Agent 服務(wù)的,不是簡單為了測通一個場景。 需要理解 Agent 的執(zhí)行模型,才能把基礎(chǔ)打牢。
![]()
第二步:Planner輸出測試計劃
操作步驟:
把 Planner 指向了數(shù)據(jù)源配置頁面,讓它生成測試計劃。提示詞如下:
@planner 為數(shù)據(jù)源配置頁面生成測試計劃。主要功能:添加 MySQL 數(shù)據(jù)源,填寫 host、port、用戶名、密碼,測試連接,保存。覆蓋異常場景:連接超時、認(rèn)證失敗、必填項為空。
Planner 確實打開了頁面,到處點點點,最后生成了一份 Markdown 計劃,看著挺全:什么“TC001 正常添加數(shù)據(jù)源”“TC002 密碼錯誤時提示”“TC003 測試連接按鈕在未填 host 時應(yīng)禁用”……
出現(xiàn)問題:
老項目里,“測試連接”按鈕的啟用/禁用邏輯根本不是由前端驗證的,而是后端實時返回的權(quán)限字段控制的。所以 Planner 生成的 TC003 在現(xiàn)實中根本不成立——因為即便 host 為空,按鈕也可能是啟用的(后端說這個用戶有權(quán)限,前端就亮著)。
如果把這個計劃直接交給 Generator 生成代碼,跑起來必然失敗,而且不是 UI 變化導(dǎo)致的失敗,是業(yè)務(wù)邏輯和 Plan 不符。
原因分析:
Planner 再聰明,它也只是一個基于可訪問性樹和頁面交互的表層探索。它看不到業(yè)務(wù)規(guī)則,看不到代碼里的 if-else 邏輯。所以它生成的測試計劃,必須要人工過濾和修正,不能全盤接收。
最后只采用了 Planner 給出的 60% 的場景,刪掉了那些涉及復(fù)雜業(yè)務(wù)規(guī)則的,自己又補了幾個真實容易出錯的邊界(比如“保存數(shù)據(jù)源時網(wǎng)絡(luò)斷開”這種 Planner 根本不會主動去測的)。
第三步:Generator 生成測試代碼
操作步驟:
Generator 根據(jù)修改后的計劃,生成了 datasource-add.spec.ts。
幾秒后,tests/datasource-add.spec.ts 生成了。我打開一看,定位符竟然用的是 getByRole 和 getByText,而不是我擔(dān)心的 hash 類名。
test('搜索無結(jié)果時顯示空狀態(tài)', async ({ page }) => { await page.goto('/users'); await page.getByRole('searchbox').fill('一個不存在的用戶名'); await page.getByRole('button', { name: '搜索' }).click(); await expect(page.getByText('暫無數(shù)據(jù)')).toBeVisible();});test('分頁切換后搜索條件應(yīng)保留', async ({ page }) => { await page.goto('/users'); await page.getByRole('searchbox').fill('張三'); await page.getByRole('button', { name: '搜索' }).click(); await page.getByLabel('第 2 頁').click(); // 驗證搜索框內(nèi)容依然是“張三” await expect(page.getByRole('searchbox')).toHaveValue('張三');});
它避開了Ant Design 3 那種 ant-select-dropdown-xxxxx 的class名,而是用了組件自帶的 ARIA 屬性(比如 getByLabel 對應(yīng) label 標(biāo)簽)。這是因為它讀取的是可訪問性樹,不是 DOM 結(jié)構(gòu)。
太爽了——這意味著即使前端升級Ant Design版本,這些定位符大概率依然有效。
出現(xiàn)問題:
當(dāng)然也有小問題。比如它生成的斷言里用了page.waitForTimeout(1000),改成了 waitForSelector。還有一個斷言期望文案是“成功”,實際接口返回的是“操作成功”,改了一下。但這些修改量很小,比自己從零寫快太多了。
總結(jié):
Generator 生成的代碼質(zhì)量已經(jīng)超過很多初級測試工程師。把它當(dāng)草稿,人工優(yōu)化斷言和等待,效率至少提升 80%。
第四步:Healer修復(fù)
生成代碼后,跑了一遍全量測試。17個測試通過了14 個,掛了3個。把失敗信息發(fā)給Healer:
@healer 修復(fù) tests/user-list.spec.ts 中失敗的用例
Healer 修復(fù)過程如下:
- 失敗 1:“測試連接”按鈕定位超時。原因是該項目的 Ant Design 3 在加載中會替換按鈕 DOM 結(jié)構(gòu),原來的 getByRole('button', { name: '測試連接' }) 找不到。Healer 重新分析了頁面,發(fā)現(xiàn)加載期間按鈕的 aria-label 變成了“加載中”,加載完成后恢復(fù)。它把定位改成了 page.getByRole('button').filter({ hasText: /測試連接|加載中/ }),并加了一個 waitForState 等待按鈕可用。重跑,通過。
- 失敗 2:保存數(shù)據(jù)源后,斷言“列表中出現(xiàn)新數(shù)據(jù)源”超時。Healer 發(fā)現(xiàn)是因為保存后列表刷新較慢,原來的 waitForSelector 超時時間太短。它自動把超時從 5 秒增加到 15 秒,并加了一個 waitForResponse 等待保存接口返回。重跑,通過。
- 失敗 3:添加重復(fù)名稱時,斷言“提示重復(fù)”失敗。Healer 嘗試了幾次,發(fā)現(xiàn)提示文案實際是“數(shù)據(jù)源名稱已存在”,而預(yù)期是“重復(fù)”。它沒有擅自改斷言,而是報告“預(yù)期文案與實際不符,請確認(rèn)業(yè)務(wù)邏輯”,然后把測試標(biāo)記為 skip。檢查了一下,發(fā)現(xiàn)是產(chǎn)品后來改了提示文字,但測試計劃沒更新。當(dāng)更新了計劃中的期望文案,重新生成,就過了。
思考:Healer 不會盲目讓測試變綠。它能區(qū)分“定位問題”“超時問題”和“業(yè)務(wù)邏輯變化”,前兩種它會自動修,第三種它不會強繞。這讓人很放心。
![]()
總結(jié)
什么人適合用?怎么用效果最好?
適合的場景:
- 你要給一個Web應(yīng)用從零開始寫E2E測試,尤其是你不熟悉業(yè)務(wù)細(xì)節(jié)的時候(Planner 幫你探索)。
- 你的項目UI頻繁變化,手動維護選擇器成本高(Healer 是真救星)。
- 你想快速驗證一個新功能的核心路徑是否穩(wěn)定(Generator 幾分鐘出一版腳本)。
不太適合的場景:
- 你的應(yīng)用有復(fù)雜的非標(biāo)準(zhǔn)交互(比如 Canvas、WebGL),Agent 可能探索不到。
- 你需要深度定制斷言邏輯(比如數(shù)據(jù)庫校驗),AI 生成的代碼只能做基礎(chǔ)驗證。
最佳實踐建議:
- Seed 測試?yán)锊灰艔?fù)雜登錄,用 storageState 保存認(rèn)證狀態(tài)。
- Planner 生成的計劃要人工過濾,它不懂你的業(yè)務(wù)優(yōu)先級。
- Generator 生成的代碼當(dāng)草稿用,斷言和等待你自己優(yōu)化一遍。
- 給 Healer 設(shè)好保護上限(比如最多自動修3次),避免它亂改預(yù)期。
- 最終代碼提交前,一定要跑一遍全量測試,確保修復(fù)沒有引入新問題。
看到這,大家還覺得AI能取代自己嗎?它只是從“寫定位符、調(diào)超時、改class 名”這種重復(fù)勞動中解放了出來。省下來的時間,去思考更深層次的測試策略,比如怎么造數(shù)據(jù)、怎么覆蓋更多邊界。
如果你也在被E2E測試折磨,花一下午試試 Playwright Test Agents。不保證完全無痛,但保證比你硬寫爽得多。
??想了解更多漲薪技能提升方法
??可以到公主號【Atstudy技術(shù)社區(qū)】,即可加入領(lǐng)取 ??????
??轉(zhuǎn)行、入門、提升、需要的各種干貨資料
??內(nèi)含AI測試、 車載測試、AI大模型開發(fā)、BI數(shù)據(jù)分析、銀行測試、游戲測試、AIGC
特別聲明:以上內(nèi)容(如有圖片或視頻亦包括在內(nèi))為自媒體平臺“網(wǎng)易號”用戶上傳并發(fā)布,本平臺僅提供信息存儲服務(wù)。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.