:從用例管理到報告通知的完整鏈路)
這兩年我看過不少團隊在做自動化測試平臺真正用起來并且越用越順的反而不多。大多數(shù)情況是測試腳本攢了一堆報告散落在各臺電腦上CI里掛幾個定時任務跑掛了靠群里有人喊一嗓子才知道。這其實不叫平臺頂多算一個“能定時執(zhí)行腳本的服務器”。我參與過一套內部自動化測試平臺的搭建設計從用例管理、任務調度、執(zhí)行環(huán)境到報告通知一條鏈路走通踩了不少坑也沉淀了一套相對可行的落地方法。這篇就是講平臺建設過程中那些真正讓人頭疼的問題以及我們最后怎么解決的適合正在規(guī)劃或已經(jīng)搭了半套測試平臺的團隊參考。1. 為什么我們需要一個真正的平臺而不僅僅是一堆腳本很多人一提自動化測試第一反應就是寫腳本。腳本當然重要但腳本解決的是“某個用例怎么跑”的問題平臺解決的是“所有用例在哪里跑、什么時候跑、跑完怎么讓所有人看到”的問題。先搞清楚這個邊界后面每一步動作都不會走偏。1.1 腳本散落一地自動化測試沒有形成資產(chǎn)團隊里有幾個人各自負責幾條業(yè)務線的接口測試腳本默認放在自己電腦上偶爾推進代碼倉庫卻不強制。于是出現(xiàn)了經(jīng)典的一幕A同學的用例要跑得先問他借電腦B同學的腳本已經(jīng)三個月沒更新接口字段早變了跑一次紅一片C同學的報告存在本地HTML文件里每次都要手動截圖發(fā)到溝通群里。剛去的時候我覺得這不是技術問題是管理問題。但深入一看根源還是沒有公共的承載入口。沒有統(tǒng)一平臺自動化測試的成果就無法沉淀。用例的版本、執(zhí)行的歷史、失敗的趨勢這些關鍵信息分散在個人電腦里領導問一句“這個季度接口自動化覆蓋率怎么樣”沒人能給出準確數(shù)字。這不是某個人的錯而是工具鏈的結構性缺失。1.2 自動化測試的價值被鎖死在“執(zhí)行”這一步自動化測試本來應該形成閉環(huán)用例編寫、定時執(zhí)行、結果分析、缺陷跟進、質量反饋。但腳本散落的時候環(huán)是斷的。定時執(zhí)行靠人肉操作結果分析靠肉眼盯屏幕質量反饋靠口頭匯報整個鏈路長、慢、全憑自覺。平臺真正解決的是把這個閉環(huán)從“人驅動”變成“數(shù)據(jù)驅動”用例統(tǒng)一入庫執(zhí)行統(tǒng)一調度結果統(tǒng)一匯總報告自動推送。誰寫的用例、什么時候改的、這次跑完跟上次比是好了還是壞了全都有據(jù)可查。自動化測試從個人的手藝活變成團隊的基礎工程設施。這一點想明白了平臺的定位自然就清楚了它不是測試工具的堆砌而是質量數(shù)據(jù)的集散地。2. 自研還是組裝三個方案對比后我們才拍板平臺建設第一步也是最容易吵起來的一步就是選型。我們當時的候選方案有三個每個看著都像模像樣但真正落地起來差別很大。2.1 三個候選方案的輪廓第一個方向是“開源CI服務 報告插件”的組合繼續(xù)用團隊已有的開源CI服務在上面配置自動化測試任務再搭一個報告展示頁面把結果聚起來。優(yōu)點是上手快CI服務團隊本來就在用不用額外引入系統(tǒng)缺點是CI服務畢竟不是為自動化測試平臺設計的用例管理、環(huán)境管理、執(zhí)行機分配這些能力要么沒有要么要自己寫一堆插件往里面貼。第二個方向是商業(yè)測試管理平臺。功能齊全開箱即用界面也漂亮缺點同樣明顯貴而且封閉。我們有些用例需要自定義執(zhí)行環(huán)境有些需要跟內部的質量數(shù)據(jù)體系做深度對接商業(yè)平臺往往不給底層接口定制一次的成本比想象中高得多。第三個方向就是自建輕量平臺從用例管理到執(zhí)行調度全部自己做。聽上去工作量最大但好處是可以完全按照團隊的工作流來設計后續(xù)所有定制需求都不受制于人。2.2 我們最終拍板自研的理由對比做完之后我們其實沒有全盤否定前兩個方向而是做了組合開源CI服務繼續(xù)保留作為通用流水線工具但自動化測試相關的用例管理、執(zhí)行調度、報告展示單獨建了一套自研平臺。為什么這么分核心原因是自動化測試平臺跟CI服務的管理模型不一樣。CI服務關注的是“代碼變更后怎么構建、怎么測試、怎么發(fā)布”以構建任務為中心而自動化測試平臺關注的是“測試用例在這個版本的代碼上表現(xiàn)如何”以用例和版本為中心。把用例直接掛在CI任務下面短期能跑長期會非常別扭用例一旦多起來任務的配置頁會爆炸誰負責哪個用例、哪些用例要在同一個環(huán)境里跑、失敗要不要自動重跑這些問題在CI配置里根本寫不清楚。自研平臺的邊界我們也畫得很清楚不做測試框架不重新發(fā)明斷言語法只做執(zhí)行管理和結果沉淀。用例腳本用什么框架寫都行平臺負責把它接進統(tǒng)一調度再把結果結構化展示出來。這個邊界讓我們避免了自研平臺最常犯的錯誤——試圖替代測試框架最后兩頭不靠。3. 平臺骨架從用例到報告的完整鏈路設計平臺建設最忌諱一上來就堆功能。我見過一些內部平臺菜單欄密密麻麻十幾個真正有人用的只有兩三個。我們的做法是先把一條主干鏈路跑通用例上傳、觸發(fā)執(zhí)行、日志回傳、報告展示、消息通知。圍繞這條鏈路設計架構再逐步補血。3.1 四層結構和三條數(shù)據(jù)流整個平臺從邏輯上可以分成四層接入層、調度層、執(zhí)行層、存儲層。接入層負責接收用例上傳和觸發(fā)請求調度層負責任務排期、并發(fā)控制、失敗重試執(zhí)行層跑在若干執(zhí)行節(jié)點上負責真正運行測試腳本存儲層保存用例元數(shù)據(jù)、執(zhí)行記錄、日志和報告附件。數(shù)據(jù)流有三條剛開始很容易被忽略。第一條是用例流轉從上傳解壓到登記入庫再到環(huán)境部署第二條是任務流轉從觸發(fā)命令生成任務記錄再到調度器分配執(zhí)行節(jié)點第三條是結果流轉執(zhí)行器把日志和結果實時回傳報告服務歸一化落庫再推送給前端和消息通道。三條數(shù)據(jù)流各自獨立又通過任務ID串聯(lián)起來排查問題的時候只要順著任務ID追就能定位到具體環(huán)節(jié)。3.2 用例管理讓腳本從“私有財產(chǎn)”變成公共資產(chǎn)用例管理模塊是第一站也是決定平臺能不能被團隊接受的關鍵。我們當時被問到最多的問題是“我把腳本傳上去還能不能在我自己電腦上跑”答案是能。平臺不是要沒收大家的腳本而是提供一份“已登記副本”。本地的隨便改平臺上的版本只通過顯式提交才會更新。具體實現(xiàn)上每份用例上傳之后平臺會生成唯一的用例編號并從壓縮包里解析出執(zhí)行入口和依賴描述文件。后端只做校驗不做改寫保證上傳的腳本和本地跑的是同一份。用例版本用遞增的數(shù)字維護每次更新都會保留上一版本執(zhí)行記錄里明確標注用的是哪個版本。這一點之后幫了大忙很多偶發(fā)失敗追到最后才發(fā)現(xiàn)是腳本版本不一致有了版本記錄這種排查時間能砍掉一半。3.3 執(zhí)行引擎隊列、并行和重試的設計執(zhí)行引擎是整個平臺里最容易出問題的地方。我們的設計很簡單觸發(fā)請求先寫成任務記錄狀態(tài)為“待執(zhí)行”調度器定期掃描待執(zhí)行任務按照優(yōu)先級和隊列策略分發(fā)給空閑執(zhí)行節(jié)點。執(zhí)行節(jié)點拿到任務之后在自己的環(huán)境里把用例跑起來結束后回傳狀態(tài)和產(chǎn)物。這里的“簡單”是事后總結的過程中反復改過三輪。最初是直接同步調用一個任務跑起來接口卡住測試人員以為平臺掛了其實只是用例還沒跑完。后來改成異步任務又面臨新的問題怎么控制同時跑多少個任務、怎么避免同一個用例被定時和手動觸發(fā)重復執(zhí)行。最終我們引入了隊列加并發(fā)信號量執(zhí)行節(jié)點回調上報調度器通過內存緩存中間件維護鎖狀態(tài)這才穩(wěn)定下來。失敗重試策略也要提前定清楚。我們是區(qū)分“斷言失敗”和“環(huán)境失敗”的斷言失敗代表業(yè)務邏輯不符重試沒有意義環(huán)境失敗比如依賴下載超時、執(zhí)行節(jié)點失聯(lián)才會觸發(fā)自動重試最多兩次。如果不區(qū)分就盲目重試遇到真正的缺陷時報告反而被掩蓋了。3.4 報告中心與通知觸達讓結果自己跑去找人報告模塊不能只是把執(zhí)行日志原樣貼出來。我們做了三個層次單次執(zhí)行的詳細報告、多次執(zhí)行的歷史對比、按項目聚合的質量趨勢。單次詳細報告包含用例狀態(tài)、失敗步驟、日志摘錄、耗時分布歷史對比展示同一個用例最近十次的通過率和平均耗時質量趨勢按周聚合整體通過率方便團隊周會上直接引用。通知的優(yōu)先級也做了設計。全量通過的任務只在報告頁更新消息通道發(fā)一條簡潔匯總出現(xiàn)失敗的任務除了匯總消息還會把失敗用例編號和日志入口帶上相關負責人在手機上就能點進去看。這里有個小經(jīng)驗不要所有結果都往群里扔不然兩天之后所有人都會把消息靜音真正重要的失敗反而被淹沒。4. 最容易被忽視的技術細節(jié)日志、環(huán)境隔離與調度一致性平臺表面上的功能誰都能做差距往往藏在細節(jié)里。下面幾個問題是我們花了最多時間處理的每一個單拿出來都值得展開說。4.1 用例日志實時回傳print只是開始最早做執(zhí)行記錄時日志是等用例跑完一次性上傳的。用例短還好跑十分鐘以上的用例測試人員盯著空白屏幕完全不知道進行到哪一步心里特別沒底。后來我們改成實時回傳執(zhí)行節(jié)點把用例進程的標準輸出流實時讀取出來按大小分塊通過長連接通道推到前端。這里有個容易踩的坑測試腳本里cout輸出經(jīng)常因為緩沖導致不能及時落盤如果只是簡單重定向到文件日志會攢一大波才刷出來。我們要求用例執(zhí)行器啟動時強制禁用輸出緩沖同時按行讀取保證前端能在幾乎實時的延遲內看到日志。再往后追加了日志級別過濾前端可以只顯示警告和報錯否則成功用例刷屏時真正有用的信息會被沖走。4.2 執(zhí)行環(huán)境隔離每次跑都像第一次跑自動化測試最怕“上次能跑這次不能跑”環(huán)境臟是頭號嫌疑犯。執(zhí)行節(jié)點如果復用全局環(huán)境不同用例之間會產(chǎn)生依賴污染A用例升級了某個依賴庫B用例再跑就掛這種問題排查起來極其崩潰。我們的做法是每條用例在獨立的臨時目錄里執(zhí)行依賴按用例聲明固定版本執(zhí)行過程中寫入的環(huán)境變量只對當前進程生效進程退出即銷毀。端口資源也做了分段分配避免并發(fā)用例搶同一個端口。這套隔離方案執(zhí)行完之后環(huán)境相關的隨機失敗率從之前的接近百分之十降到了百分之一以下。隔離帶來額外開銷比如每次執(zhí)行都要重新準備依賴但對比偶發(fā)問題浪費的排查時間這很劃算。4.3 調度與分布式鎖不讓任務重復執(zhí)行定時任務最怕什么重復執(zhí)行。我們遇到過定時觸發(fā)和手動觸發(fā)同時命中同一組用例跑了兩遍報告對不上。根因是調度器沒有做任務級別的唯一性約束。后來我們在任務生成環(huán)節(jié)加了分布式鎖用唯一鍵表示“同一用例同一觸發(fā)源在時間窗口內只能有一個待執(zhí)行任務”鎖的持有時間設置為三十分鐘超時自動釋放。同時在任務表里建了唯一索引作為兜底雙保險之后重復執(zhí)行基本絕跡。需要注意鎖的粒度要按用例維度而不是全局維度否則一個用例跑完了其他用例全被堵住并發(fā)能力直接廢掉。這個設計可以用下面這段偽代碼表達lock_key ftask_lock_{case_id}_{source} # 同一用例同一觸發(fā)源120秒內只能生成一次任務 if acquire_lock(lock_key, timeout120): create_task(case_id, source) else: log_skip(case_id, source)4.4 資源并發(fā)控制別讓一堆任務拖垮執(zhí)行節(jié)點執(zhí)行節(jié)點資源是有限的并發(fā)任務太多互相搶CPU每個用例都跑得慢最后全都超時失敗。我們給每個執(zhí)行節(jié)點設置了最大并發(fā)數(shù)調度器分配任務之前先檢查節(jié)點剩余容量超出容量的任務留在隊列里等待。這里有一點要特別提醒并發(fā)數(shù)不能只看執(zhí)行節(jié)點的物理核數(shù)還要看用例本身的特點。接口類用例輕可以多跑幾個UI自動化用例重并發(fā)稍微一高瀏覽器窗口一多內存就吃緊了。我們是按歷史執(zhí)行數(shù)據(jù)給每類用例打了資源權重輕量級用十、重量級用一權重之和不超過節(jié)點容量才允許下發(fā)。有了這套機制平臺再也不用擔心某個重任務把節(jié)點拖死。5. 從零到一落地順序先跑通再治理平臺的技術方案只是前半程真正難的是把它推進團隊日常使用。我們的落地節(jié)奏分了六個階段每一步都有明確目標。5.1 階段一盤點存量資產(chǎn)知道手里有什么動手之前先摸底。我們把團隊現(xiàn)有的自動化腳本全部盤點一遍記錄每個腳本對應的業(yè)務模塊、執(zhí)行方式、是否有依賴外部環(huán)境、上次運行時間。盤點結果很有意思大約四成的腳本已經(jīng)沒人維護跑不通真正活躍在用的只有一半左右。這個盤點幫我們避免了一個大坑——如果盲目把所有腳本都遷移到新平臺等于把一堆僵尸腳本也搬了進來平臺一上線就是一片紅大家第一印象就毀了。5.2 階段二最小閉環(huán)先行不做大而全平臺第一版只實現(xiàn)了三個功能上傳用例、手動觸發(fā)執(zhí)行、查看報告。沒有定時調度沒有消息通知也沒有復雜的權限體系。因為我們的目標是驗證一條主干鏈路能不能跑通而不是一開始就做一個完美的平臺。這三件事看著少但把用例入庫、任務生成、執(zhí)行分發(fā)、結果回傳、報告展示都串了起來后續(xù)加功能只是在這個骨架上長肉。第一版花了很短時間就交付了團隊內部試用時大家第一次體驗到“腳本傳上去就能在平臺點執(zhí)行然后直接在網(wǎng)頁上看日志”的感覺反饋比想象中積極。這個正反饋非常關鍵它讓團隊成員愿意繼續(xù)提供需求而不是把平臺當成一個行政指令下的負擔。5.3 階段三試點項目優(yōu)先讓數(shù)據(jù)說話全量推廣之前我們選了兩個核心業(yè)務線作為試點一條是接口測試用例比較成熟的另一條是UI自動化用例相對薄弱的。試點有一個明確目標連續(xù)跑兩周接口用例通過率穩(wěn)定在某個預期值以上UI用例能穩(wěn)定產(chǎn)出失敗證據(jù)。兩周試點的結果給了我們很有價值的決策依據(jù)接口用例整體通過率良好但有百分之十幾的失敗集中在依賴測試數(shù)據(jù)被清理的場景UI用例失敗里超過一半是等待超時跟被測頁面的異步加載有關系。如果沒有平臺把結果集中統(tǒng)計這些規(guī)律靠人工看散落日志根本發(fā)現(xiàn)不了。試點結束后我們用這些數(shù)據(jù)說服了還在觀望的團隊推廣阻力小了很多。5.4 階段四接進發(fā)布流程自動化測試從輔助變成門禁平臺跑順之后我們把執(zhí)行能力開放成接口接入到團隊的流水線里。流水線在部署完成后自動觸發(fā)平臺執(zhí)行冒煙測試集測試通過才允許繼續(xù)發(fā)布。這一步是自動化測試平臺價值最大化的關鍵轉折它讓測試不再是一個事后核查環(huán)節(jié)而是發(fā)布流程里的必經(jīng)關卡。剛開始接流水線時一定要輕。我們只把冒煙級別用例設為門禁回歸級別用例仍然異步執(zhí)行避免發(fā)布被大量無關失敗阻塞。等到平臺穩(wěn)定性充分驗證之后再逐步收緊。門禁的意義不只是攔問題更是給自動化測試用例提出明確的質量要求誤報率太高會被取消門禁資格測試人員為了保住門禁會主動維護用例可靠性這是平臺運營中最有價值的正向循環(huán)。5.5 階段五用例治理與運營推廣平臺不是搭完就結束后面持續(xù)運營才是重頭。我們每月做一次用例健康度檢查統(tǒng)計每個用例近三十天的執(zhí)行次數(shù)、通過率、平均耗時、最近更新時間列出一個“僵尸用例清單”發(fā)給各業(yè)務負責人。要么修要么刪不允許長期不行不維護的用例占著平臺資源。另一個運營抓手是質量周報。平臺自動生成一份按業(yè)務線分組的測試質量周報包含用例總數(shù)、執(zhí)行次數(shù)、通過率、失敗Top用例、耗時變化直接發(fā)到團隊例會材料里。質量數(shù)據(jù)一旦變成固定議程團隊對自動化測試的重視程度就完全不一樣了新增用例的行為也會越來越主動。6. 上線半年踩過的坑與排查思路平臺運行半年我們記錄了一串實際踩過的問題。每個問題單獨看似乎都不大但遇到時確實能讓整個平臺卡住下面把排查思路一并寫出來。6.1 任務消失與重復執(zhí)行狀態(tài)機與恢復機制現(xiàn)象是有時候平臺頁面上顯示“待執(zhí)行”的任務過了一段時間變成“執(zhí)行中”但執(zhí)行節(jié)點上根本沒有任何進程在跑。排查時我們先是懷疑調度器宕了檢查后發(fā)現(xiàn)是調度器重啟的時候把內存里的運行中狀態(tài)丟掉了任務既沒有重新分發(fā)也沒有被標記為失敗就一直懸在中間狀態(tài)。修復方案分兩層。第一層是把任務狀態(tài)流轉全部顯式化任何狀態(tài)的變更都必須寫數(shù)據(jù)庫調度器重啟后掃描所有“執(zhí)行中”的任務如果發(fā)現(xiàn)對應節(jié)點心跳超時就將任務重置為“待執(zhí)行”并重新分發(fā)。第二層是執(zhí)行節(jié)點增加心跳上報節(jié)點失聯(lián)超過閾值會告警避免任務卡死在失聯(lián)狀態(tài)里。加上這兩層之后任務狀態(tài)再沒出現(xiàn)過懸停。6.2 報告頁面越跑越慢分頁、異步與歸檔平臺上線兩個月后報告接口響應從一兩秒退化到十幾秒。剛開始以為是數(shù)據(jù)庫問題查了之后發(fā)現(xiàn)執(zhí)行記錄表確實漲得很快但加了索引以后效果不明顯。真正原因是前端一次性把整個任務的所有日志和截圖都渲染出來了用例一多響應體就是好幾兆。解決方案是報告接口強制分頁加按需加載列表頁只返回概要字段詳細日志按行倒序分批加載截圖文件走獨立的對象存儲鏈接不在接口響應里內嵌。另外把超過三十天的報告沉淀到歸檔存儲查詢主庫只保留活躍數(shù)據(jù)。調整之后報告頁面不管數(shù)據(jù)量多大首屏加載都控制在一兩秒內。6.3 偶發(fā)失敗最難查環(huán)境污染與共享數(shù)據(jù)有一類失敗最讓人崩潰同一個用例這次跑通過下次跑失敗看日志又完全正常。我們追蹤過好幾個案例根源幾乎都跟共享資源有關。典型的是測試用例依賴了公共測試賬號另一個用例執(zhí)行時把賬號狀態(tài)改了導致這邊登錄失敗還有一個用例讀到共享測試數(shù)據(jù)庫里的臟數(shù)據(jù)斷言的時候突然對不上。這類問題的核心解法就是徹底隔離公共賬號改造成每個任務單獨準備測試數(shù)據(jù)對象數(shù)據(jù)庫場景要求用例執(zhí)行前自己構造數(shù)據(jù)、結束后自行清理。平臺層面增加了“失敗前環(huán)境快照”在用例執(zhí)行期間采樣系統(tǒng)狀態(tài)和關鍵文件變化偶發(fā)失敗時能提供更多線索。環(huán)境治理是自動化測試長期穩(wěn)定繞不開的功課越早做越劃算。6.4 超時、等待與清理細節(jié)清單最后整理一份我們反復對團隊強調的檢查清單每條背后都有一次真實的故障案例等待元素或接口響應優(yōu)先使用輪詢等待而不是固定休眠固定休眠在環(huán)境慢的時候非常脆弱。用例超時設置不能只有一個總超時最好拆成“建立連接超時”“整體執(zhí)行超時”“用例間等待超時”分別設值。執(zhí)行結束后清理臨時文件和數(shù)據(jù)庫寫入不給后續(xù)用例留坑。用例命名必須包含業(yè)務模塊和用例編號否則報告里出現(xiàn)一堆同名“test_1”查歸屬直接崩潰。執(zhí)行節(jié)點的時間和時區(qū)要統(tǒng)一分布式環(huán)境里時間不一致調度記錄和日志排查會非常痛苦。這些細節(jié)看起來瑣碎但平臺穩(wěn)定性的提升往往不是靠一個驚天設計而是靠把這些瑣碎問題一個一個磨平。回頭總結一下這段經(jīng)歷我最大的體會是自動化測試平臺最難的部分始終不是技術而是讓團隊真正把它用起來。一上來就能被廣泛接受的平臺幾乎不存在先跑通最小閉環(huán)用數(shù)據(jù)打動觀望者再把門禁和運營機制一步步補上路子就順了。如果你想搭一套這樣的平臺別急著把界面做得花哨先讓“上傳用例、觸發(fā)執(zhí)行、看到報告”這三個動作變得無比順暢后面的事情都會自然長出來。