化回歸測(cè)試全流程)
上周接到一個(gè)需求新版 App 要上三個(gè)新增功能領(lǐng)導(dǎo)給了兩周時(shí)間要求自動(dòng)化回歸必須跟上不能只靠手工點(diǎn)點(diǎn)點(diǎn)。我當(dāng)時(shí)的方案是接口層用 pytest 和 requests 做覆蓋UI 層用 Appium 跑回歸再掛一個(gè)定時(shí)任務(wù)每天自動(dòng)執(zhí)行。實(shí)際動(dòng)手的時(shí)候大部分代碼是讓 Trae 幫我寫和改的。Trae 是一個(gè) AI 編程 IDE更準(zhǔn)確地說它可以當(dāng)作一個(gè)能理解整個(gè)項(xiàng)目上下文的輔助引擎來用。在自動(dòng)化測(cè)試這種樣板代碼多、結(jié)構(gòu)重復(fù)的場(chǎng)景里它的效率優(yōu)勢(shì)比寫業(yè)務(wù)代碼更明顯。這篇文章就把整個(gè)過程拆開講從 pytest 接口框架搭建到 Appium 回歸再到定時(shí)任務(wù)和報(bào)告通知全部是可落地、可以直接復(fù)現(xiàn)的內(nèi)容希望能給你省掉不少試錯(cuò)成本。1. Trae 在自動(dòng)化測(cè)試?yán)锏亩ㄎ慌c關(guān)鍵功能1.1 自動(dòng)化測(cè)試的痛點(diǎn)不是代碼難寫而是變更太頻繁很多人以為自動(dòng)化測(cè)試的難點(diǎn)是 Python 語法、pytest 用法或者 Appium 的 API我實(shí)際干下來的感受完全不是這樣。真正的瓶頸是“維護(hù)”接口字段一變斷言代碼跟著改頁面改版所有頁面對(duì)象里的定位符要過一遍環(huán)境地址一換公共配置到處找跑完還要整理報(bào)告、盯失敗原因。技術(shù)上每件事都不難但串在一起非常消耗時(shí)間。這正好是 AI 輔助發(fā)揮優(yōu)勢(shì)的地方。Trae 和傳統(tǒng)編輯器最大的區(qū)別是它能感知上下文我打開整個(gè)測(cè)試項(xiàng)目在對(duì)話框里直接說“把 requests 請(qǐng)求統(tǒng)一封裝成 HttpClientheader 從全局配置文件讀取”它能基于當(dāng)前目錄結(jié)構(gòu)去生成而不是給你一段孤立的示例代碼。更關(guān)鍵的是跨文件感知——新增功能通常不是只改一個(gè)文件入口、用例、數(shù)據(jù)、斷言四處都要?jiǎng)覶rae 可以把這四處關(guān)聯(lián)起來一起改。換句話說它適合的不是“寫一段教程代碼”而是“對(duì)現(xiàn)有項(xiàng)目做工程化改造”。1.2 這次實(shí)測(cè)下來最值得用的三個(gè) Trae 能力我這次用得最多、效果也最明顯的功能有三個(gè)。第一個(gè)是會(huì)話式代碼生成與重構(gòu)。以前寫一個(gè)接口的完整用例從請(qǐng)求封裝到數(shù)據(jù)驅(qū)動(dòng)到斷言至少要寫四五個(gè)文件?,F(xiàn)在把接口文檔粘貼給 Trae然后要求“按項(xiàng)目現(xiàn)有風(fēng)格生成 pytest 用例使用 yaml 數(shù)據(jù)驅(qū)動(dòng)”它生成的結(jié)構(gòu)基本能直接跑。我在實(shí)際過程中發(fā)現(xiàn)只要先給它看一兩個(gè)現(xiàn)有文件的寫法它生成的風(fēng)格和團(tuán)隊(duì)規(guī)范高度一致。第二個(gè)是跨文件搜索與批量修改。Trae 可以基于自然語言定位代碼位置例如我輸入“找出所有直接調(diào)用 requests.post 的測(cè)試文件改成走 HttpClient”它會(huì)把涉及的文件列出來逐文件改完。這個(gè)能力在做新增功能回歸時(shí)特別有用因?yàn)樾鹿δ芡鶗?huì)引入新的公共邏輯需要批量遷移舊代碼。第三個(gè)是 Trae CLI。命令行模式下可以執(zhí)行 AI 任務(wù)我主要用來做兩件事一是提交代碼前自動(dòng)跑一遍關(guān)鍵字簡(jiǎn)單檢查二是把 pytest 失敗的堆棧喂給 CLI讓 AI 先給出一個(gè)“失敗原因初步判斷”。引入到日常工作流后每天早上看報(bào)告的成本低了一個(gè)量級(jí)。話說回來Trae 也不是萬能的。它生成代碼的能力取決于你給的信息量。接口文檔、現(xiàn)有代碼風(fēng)格、依賴庫版本這三樣越明確產(chǎn)出越靠譜。后面每章我都會(huì)講到怎么通過 Prompt 把信息喂得更全。2. 用 Trae 從 0 到 1 搭建 pytest 接口自動(dòng)化框架2.1 環(huán)境準(zhǔn)備版本鎖定比“最新版”更重要如果你維護(hù)的是自己一個(gè)人用的腳本直接pip install pytest requests沒問題。但如果是團(tuán)隊(duì)項(xiàng)目我強(qiáng)烈建議把版本鎖死在 requirements.txt 里。原因很簡(jiǎn)單Trae 在生成代碼時(shí)會(huì)假設(shè)某些方法存在不同版本的 requests 和 pytest 差異雖然不大但allure-pytest恰好遇到過兼容性問題版本不鎖今天能跑明天同事一把依賴升級(jí)全部用例報(bào)錯(cuò)查起來非常浪費(fèi)時(shí)間。我這次用的依賴版本組合如下寫在 requirements.txt 里pytest7.4.0 requests2.31.0 PyYAML6.0 allure-pytest2.13.2 pytest-xdist3.3.1 appium-python-client2.11.0初始化環(huán)境python -m venv .venv source .venv/bin/activate pip install -r requirements.txt這里有一個(gè)實(shí)操細(xì)節(jié)新增功能往往還要操作數(shù)據(jù)庫做數(shù)據(jù)準(zhǔn)備建議順手裝一個(gè)pymysql但不要一開始就裝一堆用不到的庫。我踩過坑Trae 看你環(huán)境里什么庫都有容易生成一些很炫但不必要的代碼比如用 SQLAlchemy 連數(shù)據(jù)庫其實(shí)你只需要一個(gè)fetchone()。2.2 公共請(qǐng)求模塊讓 Trae 生成可復(fù)用的 HTTP 客戶端接口測(cè)試框架里最核心的模塊就是 HTTP 客戶端。它的作用是統(tǒng)一處理 base_url、token、超時(shí)、日志和請(qǐng)求頭避免每個(gè)用例里裸調(diào)requests.get/post。我給 Trae 的 Prompt 大概是這樣的“在 common/http_client.py 里生成一個(gè) HttpClient 類使用 requests.Session支持傳入 base_url 和 token提供 request 方法日志要打出請(qǐng)求方法、URL、狀態(tài)碼和耗時(shí)?!鄙珊笪疑晕⒄{(diào)整最終代碼如下# common/http_client.py import logging import time import uuid import requests class HttpClient: def __init__(self, base_url: str, token: str ): self.session requests.Session() self.base_url base_url if token: self.session.headers.update({Authorization: fBearer {token}}) self.session.headers.update({Content-Type: application/json}) def request(self, method: str, path: str, **kwargs): url f{self.base_url}{path} kwargs.setdefault(timeout, 15) request_id uuid.uuid4().hex[:8] logging.info([%s] %s %s begin, request_id, method.upper(), url) start time.time() response self.session.request(method, url, **kwargs) cost round((time.time() - start) * 1000, 2) logging.info([%s] status%s cost%sms, request_id, response.status_code, cost) return response為什么用requests.Session而不是直接requests.get因?yàn)?Session 會(huì)自動(dòng)管理連接池和 cookie接口自動(dòng)化里登錄態(tài)依賴 cookie 的場(chǎng)景特別多比如你先調(diào)登錄接口后續(xù)接口都帶著 session這比每個(gè)請(qǐng)求手動(dòng)傳 cookie 干凈得多。2.3 數(shù)據(jù)驅(qū)動(dòng)用例新增功能場(chǎng)景參數(shù)化新增功能的需求往往是同一接口要覆蓋多組參數(shù)組合比如“訂單改簽”這個(gè)場(chǎng)景可能需要測(cè)試不同的改簽時(shí)間、改簽原因、訂單狀態(tài)。如果每個(gè)組合寫一個(gè)函數(shù)代碼會(huì)膨脹到?jīng)]法維護(hù)。正確做法是用 yaml 保存測(cè)試數(shù)據(jù)用parametrize實(shí)現(xiàn)數(shù)據(jù)驅(qū)動(dòng)。先建配置文件# config/config.yaml base_url: https://api.example.com token: your_token_here新建一個(gè)通用讀取工具# common/yaml_util.py import yaml from pathlib import Path def read_yaml(path: str): abs_path Path(__file__).parent.parent / path with open(abs_path, r, encodingutf-8) as f: return yaml.safe_load(f)然后是測(cè)試數(shù)據(jù)文件# data/order_change.yaml - name: 改簽到當(dāng)天成功 order_id: A1001 change_time: 2025-06-01 14:00 reason: 個(gè)人行程變更 - name: 改簽到過去時(shí)間應(yīng)該失敗 order_id: A1002 change_time: 2025-01-01 08:00 reason: 測(cè)試用例# test_cases/test_order_change.py import pytest from common.http_client import HttpClient from common.yaml_util import read_yaml client HttpClient(https://api.example.com, your_token_here) pytest.mark.parametrize(case, read_yaml(data/order_change.yaml)) def test_order_change(case): payload { order_id: case[order_id], change_time: case[change_time], reason: case[reason], } resp client.request(POST, /api/order/change, jsonpayload) assert resp.status_code 200 data resp.json() assert data[code] 0 if case[reason] : assert data[data][status] REJECTED else: assert data[data][status] CHANGED這里我特別想讓 Trae 幫忙的是“生成用例的邊界條件”。你直接問它“這個(gè)接口還有什么邊界情況”它會(huì)根據(jù)接口文檔給出空值、超長(zhǎng)字符串、非法枚舉等補(bǔ)充建議比自己坐那兒想全快很多。不過要留個(gè)心眼AI 給的邊界條件不一定都對(duì)應(yīng)當(dāng)前版本最后還是得對(duì)一下產(chǎn)品需求和接口文檔。2.4 斷言與報(bào)告用例寫得再好報(bào)告難看也白搭斷言是自動(dòng)化測(cè)試的靈魂。很多人只寫一句assert resp.status_code 200這種用例基本是自欺欺人。接口返回 200 只代表請(qǐng)求通了不代表業(yè)務(wù)成功。我讓 Trae 生成用例的時(shí)候會(huì)明確要求“斷言必須包含業(yè)務(wù)字段校驗(yàn)”比如 code、status、關(guān)鍵業(yè)務(wù)字段的值。報(bào)告方面我習(xí)慣用 Allure因?yàn)樗恼故拘Ч麑?duì)非技術(shù)人員友好領(lǐng)導(dǎo)能一眼看懂有多少用例通過、失敗在哪個(gè)模塊。項(xiàng)目根目錄建一個(gè) pytest.ini[pytest] testpaths test_cases addopts -s -q --alluredirallure-results --clean-alluredir運(yùn)行一次pytest allure generate allure-results -o allure-report --clean allure open allure-report生成報(bào)告這個(gè)過程也可以讓 Trae 寫成一個(gè)腳本后面定時(shí)任務(wù)直接調(diào)用不用每次手敲命令。這一步看起來不起眼但它決定了自動(dòng)化測(cè)試能不能長(zhǎng)期堅(jiān)持下來——報(bào)告越容易看團(tuán)隊(duì)越愿意用用例越會(huì)被維護(hù)。3. Trae 輔助 Appium 完成移動(dòng)端新增功能回歸3.1 Appium 環(huán)境準(zhǔn)備與 capability 配置移動(dòng)端回歸比接口層麻煩因?yàn)樯婕罢鏅C(jī)或模擬器、Appium Server、UiAutomator2 三套環(huán)境。我這次用 Appium 2.0 配合 UiAutomator2capability 配置如下# app/config.py desired_caps { platformName: Android, appium:automationName: UiAutomator2, appium:deviceName: emulator-5554, appium:appPackage: com.example.app, appium:appActivity: .MainActivity, appium:noReset: True, appium:autoGrantPermissions: True, }有幾個(gè)容易忽略的點(diǎn)。第一noReset一定設(shè)成 True否則每次跑用例都清 App 數(shù)據(jù)登錄態(tài)全丟。第二autoGrantPermissions建議打開否則彈窗權(quán)限會(huì)把用例打斷。第三模擬器要提前起來并且確保adb devices能看到設(shè)備再啟動(dòng) Appium。這些配置我自己寫容易忘所以直接讓 Trae 生成一個(gè)driver_fixture.py要求它把啟動(dòng)、等待、退出都封裝進(jìn) fixture。生成的代碼大概如此# app/driver_fixture.py import pytest from appium import webdriver from app.config import desired_caps pytest.fixture(scopefunction) def driver(): driver webdriver.Remote(http://127.0.0.1:4723/wd/hub, desired_caps) driver.implicitly_wait(5) yield driver driver.quit()這里我特意把scope設(shè)置為function因?yàn)?UI 用例之間的狀態(tài)經(jīng)?;ハ喔蓴_一個(gè)用例結(jié)束就重啟會(huì)話雖然慢一點(diǎn)但可靠性高。后續(xù)如果追求執(zhí)行速度再按模塊去調(diào)整 fixture 作用域。3.2 BasePage 封裝與 Page Object 改造Appium 用例最怕的就是定位符寫成一坨直接鋪在用例里。頁面一改版幾十個(gè)用例全部要?jiǎng)?。所?Page Object 模式是移動(dòng)端自動(dòng)化標(biāo)配。我先讓 Trae 生成一個(gè)基礎(chǔ) BasePage把通用操作抽出來# app/page/base_page.py from appium.webdriver.common.appiumby import AppiumBy from selenium.webdriver.support.wait import WebDriverWait from selenium.webdriver.support import expected_conditions as EC class BasePage: def __init__(self, driver): self.driver driver self.wait WebDriverWait(driver, 15) def find_element(self, locator): return self.wait.until(EC.presence_of_element_located(locator)) def click(self, locator): self.find_element(locator).click() def send_keys(self, locator, text): element self.find_element(locator) element.clear() element.send_keys(text) def swipe_up(self, times1): size self.driver.get_window_size() x size[width] // 2 start_y int(size[height] * 0.8) end_y int(size[height] * 0.3) for _ in range(times): self.driver.swipe(x, start_y, x, end_y, 800)封裝完 BasePage 之后我讓 Trae 按同樣的風(fēng)格為新增功能頁面生成 Page Object。比如“訂單詳情頁”新增了“預(yù)計(jì)送達(dá)時(shí)間”展示我就把大概的頁面布局描述給它它生成了類似這樣的類# app/page/order_detail_page.py from appium.webdriver.common.appiumby import AppiumBy from app.page.base_page import BasePage class OrderDetailPage(BasePage): arrive_time_locator (AppiumBy.ID, com.example.app:id/tv_arrive_time) def get_arrive_time(self): return self.find_element(self.arrive_time_locator).text生成之后我做的第一件事是檢查定位符是不是真的對(duì)應(yīng)開發(fā)給到的 resource-id。AI 不會(huì)騙你但它只能根據(jù)你的描述生成一個(gè)“大概率的正確值”。3.3 一條完整的下單回歸用例是怎么組合出來的新增功能回歸不是只測(cè)新增的那幾個(gè)點(diǎn)而是要確認(rèn)新增功能沒有破壞老流程。所以我說一下完整用例的組織方式。一個(gè)端到端用例通常包含登錄、跳轉(zhuǎn)、操作、斷言四步。借用 Page Object 后用例層可以寫得非常干凈# test_cases/test_buy_flow.py import pytest from app.page.home_page import HomePage from app.page.order_detail_page import OrderDetailPage from app.page.order_page import OrderPage pytest.mark.usefixtures(driver) class TestBuyFlow: def test_create_order(self, driver): home HomePage(driver) home.click_category(數(shù)碼) home.click_first_product() detail OrderDetailPage(driver) detail.click_buy_now() order OrderPage(driver) order.confirm_order() assert order.is_order_success() # step5: 校驗(yàn)新增的預(yù)計(jì)送達(dá)時(shí)間 assert detail.get_arrive_time() ! , 預(yù)計(jì)送達(dá)時(shí)間不應(yīng)為空這種結(jié)構(gòu)的好處是用例本身只描述業(yè)務(wù)行為真正的定位符和操作細(xì)節(jié)全部在 Page Object 層。新增功能上線后主要改動(dòng)落到 page 層和少量新用例上而不是翻遍所有歷史用例。有一點(diǎn)要提醒UI 自動(dòng)化用例的斷言要比接口層更克制。不要斷言太多細(xì)節(jié)否則每條用例都異常脆弱。UI 層只要能證明“核心流程沒壞、關(guān)鍵信息有展示”就夠了把精確的字段校驗(yàn)留給接口層。這是我自己吃過大虧之后才想明白的分工。4. 讓用例每天自動(dòng)跑serverless 定時(shí)任務(wù)與報(bào)告通知4.1 為什么需要定時(shí)任務(wù)接口和 UI 用例都寫完了如果每次都要人手動(dòng)執(zhí)行自動(dòng)化測(cè)試的價(jià)值就砍掉一半。我這邊的要求是每天凌晨自動(dòng)跑全量回歸早上來公司直接看報(bào)告。實(shí)現(xiàn)方式可以選 Linux 服務(wù)器上的 crontab也可以選云廠商的 serverless 定時(shí)觸發(fā)器。兩者原理差不多都是按 cron 表達(dá)式在指定時(shí)間點(diǎn)執(zhí)行一個(gè)命令區(qū)別只是有沒有臺(tái)服務(wù)器。如果你手頭正好有測(cè)試服務(wù)器用 crontab 最直接。如果是團(tuán)隊(duì)沒有常駐服務(wù)器Serverless 定時(shí)任務(wù)更輕量按次計(jì)費(fèi)還不用維護(hù)機(jī)器。不管哪種都需要一個(gè)“一鍵執(zhí)行”的入口腳本。4.2 一鍵運(yùn)行腳本與定時(shí)觸發(fā)器配置我寫了一個(gè)run_daily.py它的職責(zé)是跑 pytest、生成報(bào)告、根據(jù)結(jié)果發(fā)通知# run_daily.py import subprocess import sys from common.notify import send_wecom_webhook if __name__ __main__: code pytest_main() # 生成 allure 報(bào)告 subprocess.run([allure, generate, allure-results, -o, allure-report, --clean]) if code 0: send_wecom_webhook(https://qyapi.weixin.qq.com/cgi-bin/webhook/send?keyxxxx, 自動(dòng)化測(cè)試全部通過) else: send_wecom_webhook(https://qyapi.weixin.qq.com/cgi-bin/webhook/send?keyxxxx, 自動(dòng)化測(cè)試有失敗請(qǐng)查看報(bào)告) sys.exit(code) def pytest_main(): import pytest return pytest.main([-s, -q, test_cases, --alluredirallure-results, --clean-alluredir])如果使用 crontab配置如下0 1 * * * cd /opt/autotest python run_daily.py logs/daily.log 21這個(gè) cron 表達(dá)式的意思是每天凌晨 1 點(diǎn)執(zhí)行一次。關(guān)鍵點(diǎn)是一定要把日志重定向到文件里。實(shí)際出現(xiàn)過定時(shí)任務(wù)跑掛了但因?yàn)樵诮K端里直接跑正常所以一直沒發(fā)現(xiàn)直到加了日志才知道是環(huán)境變量缺失導(dǎo)致命令找不到。日志是排查定時(shí)任務(wù)問題的最好朋友。如果走 Serverless原理是一樣的在控制臺(tái)創(chuàng)建函數(shù)運(yùn)行環(huán)境選 Python入口設(shè)置為run_daily.index然后配置定時(shí)觸發(fā)器cron 表達(dá)式寫0 1 * * * *。函數(shù)執(zhí)行完會(huì)返回日志比服務(wù)器上查日志更方便。4.3 測(cè)試報(bào)告輸出與機(jī)器人通知報(bào)告生成之后不能讓工程師自己登錄服務(wù)器看。最簡(jiǎn)單的做法是接一個(gè)企業(yè)微信群機(jī)器人通過 webhook 把結(jié)果文本推送到群里。核心代碼# common/notify.py import requests def send_wecom_webhook(webhook_url: str, content: str): body { msgtype: text, text: {content: content} } requests.post(webhook_url, jsonbody, timeout10)通知文本不要只寫“成功/失敗”我會(huì)讓 Trae 生成一段小工具從 allure-results 目錄里統(tǒng)計(jì)失敗用例名然后拼進(jìn)去。這樣群里看到消息就知道是哪個(gè)模塊掛了不用再打開報(bào)告翻半天。通知這個(gè)環(huán)節(jié)很容易被忽略但它決定了自動(dòng)化測(cè)試能不能“被”用起來。5. 常見問題與排查技巧實(shí)錄5.1 我踩過的幾個(gè)坑第一Trae 生成了代碼里不存在的 API。比如它可能在 pytest 里用了一個(gè)自定義 fixture但我沒定義同名 fixture跑用例直接報(bào)錯(cuò)?,F(xiàn)在我每次讓 Trae 生成代碼都會(huì)加一句“只使用項(xiàng)目已有依賴庫和已有文件不得假設(shè)額外模塊存在”這句話能顯著減少返工。第二生成用例時(shí)fixture 作用域沒搞清導(dǎo)致數(shù)據(jù)污染。Trae 默認(rèn)生成的 fixture 往往是scopefunction但接口自動(dòng)化里登錄態(tài)可能希望是session級(jí)別。如果混用很容易出現(xiàn)“用例單獨(dú)跑通過全量跑失敗”的詭異問題。建議生成后立刻檢查 fixture 的作用域。第三Appium 定位等待方式不對(duì)。presence_of_element_located和visibility_of_element_located是兩回事某些情況下元素在 DOM 里存在但不可見用 visibility 才會(huì)等到正確狀態(tài)。AI 默認(rèn)生成的代碼不一定符合實(shí)際場(chǎng)景這條尤其要人工校驗(yàn)。第四定時(shí)任務(wù)運(yùn)行環(huán)境與本地不一致。本地跑 pytest 能找到命令云函數(shù)環(huán)境里卻找不到 spawn 的 allure因?yàn)榄h(huán)境變量不同。我的解決方法是腳本里用絕對(duì)路徑或者把 allure 調(diào)用封裝成在函數(shù)內(nèi)通過shutil.which探測(cè)。5.2 問題排查速查表我把這段時(shí)間遇到的典型問題整理成一個(gè)表方便你直接對(duì)照現(xiàn)象可能原因排查看法pytest 一個(gè)用例都沒執(zhí)行testpaths 配錯(cuò)或文件名不是 test_ 開頭先pytest --collect-only看收集結(jié)果用例單獨(dú)跑通過全量跑失敗fixture 作用域沖突或用例間共享數(shù)據(jù)被改寫檢查是否有 module 級(jí) fixture 修改了全局狀態(tài)Appium 定位不到元素resource-id 對(duì)不上或元素在另一個(gè) WebView用 Appium Inspector 看當(dāng)前頁面 UI 層級(jí)定時(shí)任務(wù)沒跑cron 時(shí)間格式錯(cuò)誤、腳本無執(zhí)行權(quán)限、環(huán)境變量缺失先看腳本日志再手動(dòng)執(zhí)行入口腳本對(duì)比Trae 生成的斷言太弱沒有明確要求業(yè)務(wù)斷言重新生成時(shí)要求“必須校驗(yàn) code 和狀態(tài)字段”Allure 報(bào)告為空allure-results 路徑不一致確認(rèn) pytest.ini 的 addopts 與實(shí)際報(bào)告路徑一致5.3 給新人的一個(gè)團(tuán)隊(duì)協(xié)作建議如果你不是一個(gè)人維護(hù)這套東西建議在項(xiàng)目里沉淀一個(gè)docs/prompt-template.md把常用的 Trae 提示詞規(guī)范寫下來。比如“生成用例時(shí)必須使用 data 目錄下的 yaml 數(shù)據(jù)驅(qū)動(dòng)”“發(fā)送請(qǐng)求必須走 HttpClient”“不得假設(shè)額外依賴庫”。這樣不管是老同事還是新同學(xué)生成的代碼風(fēng)格都是一致的Long-term維護(hù)成本會(huì)低很多。另一個(gè)小技巧是讓 Trae 順手生成“用例和需求單號(hào)”的映射注釋。新增功能往往對(duì)應(yīng)產(chǎn)品需求單把單號(hào)寫進(jìn)用例注釋里將來需求變更、字段調(diào)整時(shí)你能快速找到是哪批用例要改。這個(gè)細(xì)節(jié)幫我省過好幾次返工。最后說點(diǎn)個(gè)人體會(huì)。Trae 這類工具真正改變的是我做自動(dòng)化測(cè)試的手感以前碰到大改版至少兩三天耗在改定位符和公共方法上現(xiàn)在可以把相當(dāng)一部分機(jī)械工作丟給 AI我集中精力看用例邏輯和邊界條件。但記得一條AI 寫出來的測(cè)試代碼一定要親自走一遍數(shù)據(jù)流尤其要檢查斷言是不是真的能抓到問題。如果斷言寫得淺AI 生成一百個(gè)用例也救不了后臺(tái)那幾行 bug。希望這篇攻略能讓你下次接新增功能時(shí)少熬幾個(gè)夜。