前言
最近一年多一直在做前端的一些測試,從小程序到店鋪裝修,基本都是純前端的工作,剛開始從后端測試轉為前端測試的時候,對前端東西茫然無感,而且團隊內沒有人做過純前端的測試工作,只能一邊踩坑一邊總結經(jīng)驗,然后將容易出現(xiàn)問題的點形成體系、不斷總結摸索,最終形成了目前的一套前端測試解決方案。在此,將有贊的前端質量保障體系進行總結,希望和大家一起交流。
先來全局看下有贊前端的技術架構和針對每個不同的層次,主要做了哪些保障質量的事情:


有贊的 Node 技術架構分為業(yè)務層、基礎框架層、通用組件和基礎服務層,我們日常比較關注的是基礎框架、通用組件和業(yè)務層代碼。Node 業(yè)務層做了兩件事情,一是提供頁面渲染的 client 層,用于和 C 端用戶交互,包括樣式、行為 js 等;二是提供數(shù)據(jù)服務的 server 層,用于組裝后臺提供的各種接口,完成面向 C 端的接口封裝。
對于每個不同的層,我們都做了一些事情來保障質量,包括:
- 針對整個業(yè)務層的 UI 自動化、核心接口|頁面撥測;
- 針對 client 層的 sentry 報警;
- 針對 server 層的接口測試、業(yè)務報警;
- 針對基礎框架和通用組件的單元測試;
- 針對通用組件變更的版本變更報警;
- 針對線上發(fā)布的流程規(guī)范、用例維護等。
下面就來分別講一下這幾個維度的質量保障工作。
一、UI自動化
很多人會認為,UI 自動化維護成本高、性價比低,但是為什么在有贊的前端質量保證體系中放在了最前面呢?
前端重用戶交互,單純的接口測試、單元測試不能真實反映用戶的操作路徑,并且從以往的經(jīng)驗中總結得出,因為各種不可控因素導致的發(fā)布 A 功能而 B 功能無法使用,特別是核心簡單場景的不可用時有出現(xiàn),所以每次發(fā)布一個應用前,都會將此應用提供的核心功能執(zhí)行一遍,那隨著業(yè)務的不斷積累,需要回歸的測試場景也越來越多,導致回歸的工作量巨大。為了降低人力成本,我們亟需通過自動化手段釋放勞動力,所以將核心流程回歸的 UI 自動化提到了最核心地位。
當然,UI 自動化的最大痛點確實是維護成本,為降低維護成本,我們將頁面分為組件維度、頁面維度,并提供統(tǒng)一的包來處理公用組件、特殊頁面的通用邏輯,封裝通用方法等,例如初始化瀏覽器信息、環(huán)境選擇、登錄、多網(wǎng)點切換、點擊、輸入、獲取元素內容等等,業(yè)務回歸用例只需要關注自己的用例操作步驟即可。
1.框架選擇
-- puppeteer[1],它是由 Chrome 維護的 Node 庫,基于 DevTools 協(xié)議來驅動 chrome 或者 chromium 瀏覽器運行,支持 headless 和 non-headless 兩種方式。官網(wǎng)提供了非常豐富的文檔,簡單易學。
UI 自動化框架有很多種,包括 selenium、phantom;對比后發(fā)現(xiàn) puppeteer 比較輕量,只需要增加一個 npm 包即可使用;它是基于事件驅動的方式,比 selenium 的等待輪詢更穩(wěn)當、性能更佳;另外,它是 chrome 原生支持,能提供所有 chrome 支持的 api,同時我們的業(yè)務場景只需要覆蓋 chrome,所以它是最好的選擇。
-- mocha[2] + mochawesome[3],mocha 是比較主流的測試框架,支持 beforeEach、before、afterEach、after 等鉤子函數(shù),assert 斷言,測試套件,用例編排等。
mochawesome 是 mocha 測試框架的第三方插件,支持生成漂亮的 html/css 報告。
js 測試框架同樣有很多可以選擇,mocha、ava、Jtest 等等,選擇 mocha 是因為它更靈活,很多配置可以結合第三方庫,比如 report 就是結合了 mochawesome 來生成好看的 html 報告;斷言可以用 powser-assert 替代。
2.腳本編寫
- 封裝基礎庫
- 封裝 pc 端、h5 端瀏覽器的初始化過程
- 封裝 pc 端、h5 端登錄統(tǒng)一處理
- 封裝頁面模型和組件模型
- 封裝上傳組件、日期組件、select 組件等的統(tǒng)一操作方法
- 封裝 input、click、hover、tap、scrollTo、hover、isElementShow、isElementExist、getElementVariable 等方法
- 提供根據(jù) “html 標簽>>頁面文字” 形式獲取頁面元素及操作方法的統(tǒng)一支持
- 封裝 baseTest,增加用例開始、結束后的統(tǒng)一操作
- 封裝 assert,增加斷言日志記錄
- 業(yè)務用例
- 安裝基礎庫
- 編排業(yè)務用例
3.執(zhí)行邏輯
- 分環(huán)境執(zhí)行
- 增加預上線環(huán)境代碼變更觸發(fā)、線上環(huán)境自動執(zhí)行
- 監(jiān)控源碼變更
- 增加 gitlab webhook,監(jiān)控開發(fā)源碼合并 master 時自動在預上線環(huán)境執(zhí)行
- 增加 gitlab webhook,監(jiān)控測試用例變更時自動在生產環(huán)境執(zhí)行
- 每日定時執(zhí)行
- 增加 crontab,每日定時執(zhí)行線上環(huán)境




二、接口測試
接口測試主要針對于 Node 的 server 層,根據(jù)我們的開發(fā)規(guī)范,Node 不做復雜的業(yè)務邏輯,但是需要將服務化應用提供 dubbo 接口進行一次轉換,或將多個 dubbo 接口組合起來,提供一個可供 h5/小程序渲染數(shù)據(jù)的 http 接口,轉化過程就帶來了各種數(shù)據(jù)的獲取、組合、轉換,形成了新的端到端接口。這個時候單單靠服務化接口的自動化已經(jīng)不能保障對上層接口的全覆蓋,所以我們針對 Node 接口也進行自動化測試。為了使用測試內部統(tǒng)一的測試框架,我們通過 java 去請求 Node 提供的 http 接口,那么當用例都寫好之后,該如何評判接口測試的質量?是否完全覆蓋了全部業(yè)務邏輯呢?此時就需要一個行之有效的方法來獲取到測試的覆蓋情況,以檢查有哪些場景是接口測試中未覆蓋的,做到更好的查漏補缺。
istanbul[4] 是業(yè)界比較易用的 js 覆蓋率工具,它利用模塊加載的鉤子計算語句、行、方法和分支覆蓋率,以便在執(zhí)行測試用例時透明的增加覆蓋率。它支持所有類型的 js 覆蓋率,包括單元測試、服務端功能測試以及瀏覽器測試。
但是,我們的接口用例寫在 Java 代碼中,通過 Http 請求的方式到達 Node 服務器,非 js 單測,也非瀏覽器功能測試,如何才能獲取到 Node 接口的覆蓋率呢?
解決辦法是增加 cover 參數(shù):--handle-sigint,通過增加 --handle-sigint 參數(shù)啟動服務,當服務接收到一個 SIGINT 信號(linux 中 SIGINT 關聯(lián)了 Ctrl+C),會通知 istanbul 生成覆蓋率。這個命令非常適合我們,并且因此形成了我們接口覆蓋率的一個模型:
1. istanbule --handle-sigint 啟動服務
2. 執(zhí)行測試用例
3. 發(fā)送 SIGINT結束istanbule,得到覆蓋率
最終,解決了我們的 Node 接口覆蓋率問題,并通過 jenkins 持續(xù)集成來自動構建



當然,在獲取覆蓋率的時候有需求文件是不需要統(tǒng)計的,可以通過在根路徑下增加 .istanbule.yml 文件的方式,來排除或者指定需要統(tǒng)計覆蓋率的文件
verbose: false
instrumentation:
root: .
extensions:
- .js
default-excludes: true
excludes:['**/common/**','**/app/constants/**','**/lib/**']
embed-source: false
variable: __coverage__
compact: true
preserve-comments: false
complete-copy: false
save-baseline: false
baseline-file: ./coverage/coverage-baseline.json
include-all-sources: false
include-pid: false
es-modules: false
reporting:
print: summary
reports:
- lcov
dir: ./coverage
watermarks:
statements: [50, 80]
lines: [50, 80]
functions: [50, 80]
branches: [50, 80]
report-config:
clover: {file: clover.xml}
cobertura: {file: cobertura-coverage.xml}
json: {file: coverage-final.json}
json-summary: {file: coverage-summary.json}
lcovonly: {file: lcov.info}
teamcity: {file: null, blockName: Code Coverage Summary}
text: {file: null, maxCols: 0}
text-lcov: {file: lcov.info}
text-summary: {file: null}
hooks:
hook-run-in-context: false
post-require-hook: null
handle-sigint: false
check:
global:
statements: 0
lines: 0
branches: 0
functions: 0
excludes: []
each:
statements: 0
lines: 0
branches: 0
functions: 0
excludes: []
三、單元測試
單元測試在測試分層中處于金字塔最底層的位置,單元測試做的比較到位的情況下,能過濾掉大部分的問題,并且提早發(fā)現(xiàn) bug,也可以降低 bug 成本。推行一段時間的單測后發(fā)現(xiàn),在有贊的 Node 框架中,業(yè)務層的 server 端只做接口組裝,client 端面向瀏覽器,都不太適合做單元測試,所以我們只針對基礎框架和通用組件進行單測,保障基礎服務可以通過單測排除大部分的問題。比如基礎框架中店鋪通用信息服務,單測檢查店鋪信息獲取;比如頁面級商品組件,單測檢查商品組件渲染的 html 是否和原來一致。
單測方案試行了兩個框架:
- Jest[5]
- ava[6]
比較推薦的是 Jest 方案,它支持 Matchers 方式斷言;支持 Snapshot Testing,可測試組件類代碼渲染的 html 是否正確;支持多種 mock,包括 mock 方法實現(xiàn)、mock 定時器、mock 依賴的 module 等;支持 istanbule,可以方便的獲取覆蓋率。
總之,前端的單測方案也越來越成熟,需要前端開發(fā)人員更加關注 js 單測,將 bug 扼殺在搖籃中。
四、基礎庫變更報警
上面我們已經(jīng)對基礎服務和基礎組件進行了單元測試,但是單測也不能完全保證基礎庫的變更完全沒有問題,伴隨著業(yè)務層引入新版本的基礎庫,bug 會進一步帶入到業(yè)務層,最終影響 C 端用戶的正常使用。那如何保障每次業(yè)務層引入新版本的基礎庫之后能做到全面的回歸?如何讓業(yè)務測試同學對基礎庫變更更加敏感呢?針對這種情況,我們著手做了一個基礎庫版本變更的小工具。實現(xiàn)思路如下:
1. 對比一次 master 代碼的提交或 merge 請求,判斷 package.json 中是否有特定基礎庫版本變更
2. 將對應基礎庫的前后兩個版本的代碼對比發(fā)送到測試負責人
3. 根據(jù) changelog 判斷此次回歸的用例范圍
4. 增加 gitlab webhook,只有合并到合并發(fā)布分支或者 master 分支的代碼才觸發(fā)檢查
這個小工具的引入能及時通知測試人員針對什么需求改動了基礎組件,以及這次基礎組件的升級主要影響了哪些方面,這樣能避免相對黑盒的測試。
第一版實現(xiàn)了最簡功能,后續(xù)再深挖需求,可以做到前端代碼變更的精準測試。

五、sentry報警
在剛接觸前端測試的時候,js 的報錯沒有任何追蹤,對于排查問題和定位問題有很大困擾。因此我們著手引入了 sentry 報警監(jiān)控,用于監(jiān)控線上環(huán)境 js 的運行情況。
sentry[7] 是一款開源的錯誤追蹤工具,它可以幫助開發(fā)者實時監(jiān)控和修復崩潰。
開始我們接入的方式比較簡單粗暴,直接全局接入,帶來的問題是報警信息非常龐大,全局上報后 info、warn 信息都會打出來。
更改后,使用 sentry 的姿勢是:
- sentry 的全局信息上報,并進行篩選
- 錯誤類型: TypeError 或者 ReferenceError
- 錯誤出現(xiàn)用戶 > 1k
- 錯誤出現(xiàn)在 js 文件中
- 出現(xiàn)錯誤的店鋪 > 2家
- 增加核心業(yè)務異常流程的主動上報
最終將篩選后的錯誤信息通過郵件的形式發(fā)送給告警接收人,在固定的時間集中修復。


六、業(yè)務報警
除了 sentry 監(jiān)控報警,Node 接口層的業(yè)務報警同樣是必不可少的一部分,它能及時發(fā)現(xiàn) Node 提供的接口中存在的業(yè)務異常。這部分是開發(fā)和運維同學做的,包括在 Node 框架底層接入日志系統(tǒng);在業(yè)務層正確的上報錯誤級別、錯誤內容、錯誤堆棧信息;在日志系統(tǒng)增加合理的告警策略,超過閾值之后短信、電話告警,以便于及時發(fā)現(xiàn)問題、排查問題。
業(yè)務告警是最能快速反應生產環(huán)境問題的一環(huán),如果某次發(fā)布之后發(fā)生告警,我們第一時間選擇回滾,以保證線上的穩(wěn)定性。
七、約定規(guī)范
除了上述的一些測試和告警手段之外,我們也做了一些流程規(guī)范、用例維護等基礎建設,包括:
- 發(fā)布規(guī)范
- 多個日常分支合并發(fā)布
- 限制發(fā)布時間
- 規(guī)范發(fā)布流程
- 整理自測核心檢查要點
- 基線用例庫
- 不同業(yè)務 P0 核心用例定期更新
- 項目用例定期更新到業(yè)務回歸用例庫
- 線上問題場景及時更新到回歸用例庫
目前有贊的前端測試套路基本就是這樣,當然有些平時的努力沒有完全展開,例如接口測試中增加返回值結構體對比;增加線上接口或頁面的撥測[8];給開發(fā)進行自測用例設計培訓等等。也還有很多新功能探索中,如接入流量對比引擎,將線上流量導到預上線環(huán)境,在代碼上線前進行對比測試;增加UI自動化的截圖對比;探索小程序的UI自動化等等。
參考鏈接:
- [1] https://github.com/GoogleChrome/puppeteer
- [2] https://www.npmjs.com/package/mocha
- [3] https://www.npmjs.com/package/mochawesome
- [4] https://github.com/gotwarlost/istanbul
- [5] https://github.com/facebook/jest
- [6] https://github.com/avajs/ava
- [7] https://docs.sentry.io
- [8] https://tech.youzan.com/youzan-online-active-testing/
