飛書視訊會議端到端整合測試工程實踐經驗總結 - Zadig 應用案例

語言: CN / TW / HK

Zadig 推薦語:“先進團隊,先用飛書“,在激烈競爭的協同辦公市場,飛書以一匹黑馬的姿態殺入,並在短期內收穫了“好用”的評價,被眾多優秀的企業採用。隨著飛書產品的演進和成熟,背後的質量工程也挑戰重重,經過多年的實踐和探索,他們沉澱了一套面向音視訊領域獨特的建設思路和寶貴的實踐經驗,Enjoy!

筆者介紹:吳國華,曾在微軟 BingAds 從事 SRE 相關工作,專注研發效能、整合測試、容災穩定性等相關領域。現在位元組跳動飛書視訊會議團隊擔任 Tech Leader,負責 SIP 業務線的技術架構、穩定性和質量保障等相關領域。

業務介紹

作為早期加入飛書視訊會議(VideoConference,簡稱 VC)團隊的員工,我基本見證了飛書視訊會議產品從 0 到 1 的發展過程。飛書視訊會議團隊成立於 2018 年的年中,在成立之始,我們眼前就已經有像Zoom、Webex 這樣的大山。想要在這個領域創新,是極為不易的。

但幸運的是,飛書的優勢更在於一體化的套件。“套件戰勝單品”是我們重要的戰略思路,飛書擁有 IM、文件、日曆、郵件、審批、People、百科、小程式、視訊會議等等豐富多彩的功能模組,貫穿企業辦公的方方面面。也許單看某一項功能,飛書可能不如競品,但作為套件整體來說,飛書擁有極為流暢的一體化體驗:例如飛書文件中可以分享飛書 IM 群組、飛書視訊會議中可以直接投屏飛書文件、飛書日曆中可以預約飛書視訊會議等等。

由此可以看出,飛書的定位是“All in One”全家桶,我們的目標或者說願景是成為企業辦公套件領域的 No.1。

隨著飛書自身的向上發展,套件各個模組之間可以互相借力,出色的模組又可以反向帶動飛書繼續向上發展,形成良性迴圈。因此在這樣的基礎之上,雖然挑戰很大,但我們依舊對從 0 到 1 開始做飛書視訊會議產品抱有信心。

綜上所述,基於飛書整體的戰略思路,我們秉承“先快後穩”的產品路線。時至今日,我們陸續創立了:飛書會議、飛書會議室、飛書SIP/H.323會議室聯結器、飛書妙記、飛書直播等等音視訊產品矩陣。

體系建設

回顧業務產品發展的歷史程序,可以總結為三個大階段:快速迭代、鼓勵創新、專注品質

  • 快速迭代(初創期):我們從將 VC 整合入飛書(即飛書會議)著手開始探索並快速迭代功能。這個時期雖然人員、技術、流程發展迅速,但整體處於初級階段,因此質量 baseline 較低。
  • 鼓勵創新(產品突破期):我們希望通過創新來彎道超車競品,因此陸續開啟多項探索型工作。例如:飛書會議獨立 App、飛書妙享、飛書妙記、會議 AI 特效、字幕等等。與此同時,專職 QA 團隊成立,技術、流程、規範都陸續趨於成熟,質量最終能夠提升。但始終缺乏對線上變更的實時檢測能力,導致質量忽高忽低,波動明顯
  • 專注品質(商業化期):我們基本完成了目標客戶的大部分卡點需求,因此品質成為重點,對不發生嚴重事故的提出高要求。也是在這個時候,我們引入了端到端自動化測試(即本文想要重點介紹的)、音視訊品質測試、各機型硬體相容性測試等等手段,質量穩步提升。

抽象地說,如果以質量作為評價標準,那麼,我們在這三大階段的趨勢大致如下:

而經過長期的探索,我們也建立以流程、資料、測試為核心的質量保障體系,本文重點介紹測試工程:

漫談測試

首先我想強調:測試是手段,質量才是目標

很多人認為測試 = 測試自動化,或者認為只有測試自動化了才能保障質量,這是一種比較常見的誤區,忽略了測試自動化本身的成本。做業務的同學應該能理解,時間是影響業務成功的重要因素,我們不能一味追求測試自動化而忽視產品爭取市場的關鍵節點,這是典型的技術驅動產品。事實上,飛書包括位元組整體都有相當數量的 QA,手動測試和自動化測試我們同樣看重

另一個比較普遍的誤區是當一個團隊有專職的 QA 之後,大家會習慣性將所有與測試相關的責任全部歸在 QA 身上,這是一種工程上的短視。相信大家都聽過 DevOps 這個詞,DevOps 是一種文化,涵蓋了軟體交付生命週期的全流程,讓研發人員和運維人員觀念達成一致,打破所謂的職責邊界。對測試的態度同樣如此,優秀的工程師會把開發思維、測試思維、運維思維貫徹始終,而不是糾結誰的職責是什麼。

其次我想強調:測試是多元化的

多元化的第一個體現是上面提到的:測試不應侷限於自動化,手動測試一樣是重要手段。而且,並不是所有業務場景都能做測試自動化。以 VC 為例,很多特定型號的第三方硬體終端並不提供 OpenAPI 的支援,因此無法進行自動化,這種情況下手動測試就是唯一的選擇。

多元化的第二個體現是:測試的粒度。相信大家都聽過單元測試、整合測試、系統測試等等名詞,這裡面表述的是對不同測試粒度的稱呼。一般來說,測試粒度越細,測試用例就越依賴於打樁(指代以 mock 為主的技術手段,來模擬外部依賴的返回值),測試穩定性就越好,但相對的測試模擬程度就越低。隨著測試粒度不斷提升,帶來的收益就是效果會越接近於使用者的真實體驗,但測試穩定性會越差,成本也會越高。不同粒度的測試側重點不同,它們之間不是互斥的,事實上它們通常會同時存在於系統中。

多元化的第三個體現是:測試的階段。對新功能的測試和對現有功能的測試思路是不一樣的,尤其當全部的測試集比較龐大的時候。通常來說對於新功能,我們認為所有場景的用例都需要覆蓋至少一次;而對於現有功能的測試,我們則會在日常回歸中覆蓋主場景。複雜的系統需要對測試用例進行分級,以 VC為例,我們根據不同的業務場景重要性將測試全集劃分為 P0/P1/P2/P3 等級別,日常回歸重點覆蓋P0/P1。總之,不同的測試階段重點不同,測試成本也不同,我們需要結合實際情況來運用不同的方法。

明確目標

正因為測試是多元化的,測試最終目的是保障質量。所以我們更加需要了解所在的環境下目前缺少的是什麼,我們希望做一套什麼樣的測試實踐,我們的手段是手動還是自動化,我們主要針對的測試環境、測試粒度和測試階段是什麼。即我們需要一個清晰可描述可達的目標

那麼回到這裡,為什麼我們會想到做這樣一套端到端自動化測試呢?

我們的原始動機是因為缺乏對線上變更的實時檢測能力。更具體地說,我們曾一度因為突發的變更,如:動態配置變更、基礎設施變更、機房網路抖動等等原因,發生過嚴重事故。雖然這些變更也會觸發各自的監控告警,但我們更希望從使用者的角度來看實際的影響。

因此從這個基點出發,我們想到的是引入一套常駐的迴圈測試機制(PS:所以可以看出不是手動而是自動化),模擬視訊會議的使用者行為,來保障不發生嚴重事故。

當我跟別人談起要做一套針對飛書VC端到端自動化測試的時候,不少人上來就問:“那麼你用的是什麼測試框架?GoConvey 還是 Ginkgo?(PS:位元組服務端主要是 Go 技術棧)”,這樣的問題其實看似簡單直白,但問題的答案對於理解這套測試實踐其實沒有太大幫助。比起這個,更重要的是這套測試實踐針對什麼場景。

因為我們不是要設計一套自動化測試框架去統一世界,然後不惜一切代價去替換其它不同維度的自動化測試

經過一段時間的調研,我們開始逐步明確新框架的定位。

首先思考的是測試粒度。我在位元組跳動飛書為什麼選擇 Zadig 實現主幹開發、主幹釋出 一文中曾經介紹了我們在單元測試和微服務整合測試的思考實踐,因此當下我們缺乏的是粒度更粗更接近使用者真實體驗的端到端測試,即從音視訊客戶端到音視訊服務端全鏈路的測試。

其次思考的是測試內容。在視訊會議的業務場景下,連通品質是兩個完全不同的測試方向。用直白的話來說,連通指代的是“聽不見、看不見”即未成功加入房間,品質指代的是“聽不清楚、畫面模糊”即加入房間但體驗不順。由於品質差的直接原因 90% 以上是終端網路環境差,所以在嚴重程度上,我們會更高優去看連通問題。我們經過反覆討論之後,決定主要針對連通問題來設計框架,而品質測試則引入專業的音視訊實驗室裝置(例如:網損儀)來推進。

第三個重要思考是測試客戶端。不同於模擬 API 請求直接傳送給服務端的測試方式,當我們考慮端到端全鏈路的時候,我們需要重點考慮客戶端的技術實現。這裡面的爭議點主要在於是直接用真機測試還是用虛擬程序測試。從模擬程度來看,無疑是直接用真機更好,但真機的機型繁多,購買真機成本很高,無法滿足大方數會議的測試場景。另一個真機的致命問題是穩定性較差,真機不比虛擬程序,往往還依賴各硬體自身的穩定性,尤其是當真機處於網路條件差的情況下會有五花八門的問題撲面而來。因此,我們在慎重的決策之後,選擇基於虛擬程序,即虛擬客戶端來進行測試。

第四個重要思考是測試環境和測試階段。從我們建立這套測試的動機來看,我們需要直接對生產環境發起測試,同時 7x24 小時無間斷重複性觸發。關於直接對著生產環境測試這一點,可能會引發一些爭議。所以我在這裡澄清一下,飛書有租戶的概念,各租戶之間在生產環境是隔離的,我們可以建立測試租戶來落地自動化測試。

總結一下,在經過一系列的思考討論之後,我們對新框架的定位基本明確:這是一套端到端全鏈路的、針對連通性、基於虛擬程序、直接面向生產環境、7x24 小時無間斷的測試實踐。

框架設計

當目標明確到清晰可達之後,我們就開始著手設計測試框架,最終的框架設計結構大概如下:

  • Automation 平臺:基於開源元件 Zadig 搭建的一套整合測試平臺,用於提供定時執行測試集、隔離不同測試集環境、測試集結果展示與分析、測試集失敗通知與告警等等能力
  • E2E 測試框架:基於 Go 語言自研的 E2E 測試框架,對測試開發提供友好的封裝與抽象,簡化測試用例編寫與維護
    • AutomationAPI:E2E 測試框架封裝的原子 API,控制終端裝置行為
    • AutomationAPICallback:E2E 測試框架封裝的原子 APICallback,終端裝置產生的結果
  • Automation 中心服務:執行在核心機房的控制中心,集中轉發 API 和 Callback
  • Automation Worker:執行在邊緣機房的工作節點,管理並建立虛擬客戶端,與中心服務互動 API 和Callback

概括來說,這套框架核心在於:可以大規模動態建立 VC 虛擬客戶端,且虛擬客戶端能夠被 API 化,測試結果能夠被 Callback 化

服務架構如下:

AutomationAPIAutomationAPICallback 是整套測試實踐中的兩個核心抽象概念:API 是對 VC 客戶端控制指令的抽象,例如:入會、釋出音視訊流、訂閱音視訊流、麥克風靜音/解除、攝像頭開啟/關閉等等使用者動作;APICallback 則是觸發使用者動作之後,會議房間產生的事件,例如:建立會議事件、接入閘道器事件、入會事件、推流事件、拉流事件、離會事件等等。

我們在框架層提供了對 API 和 APICallback 的封裝,暴露給測試開發更加貼近業務、更加友好的呼叫方式。測試開發只需要在測試用例中組合 API,觀測 APICallback,對各個階段進行斷言,即可完成測試。

框架實踐

經過一段時間的開發之後,我們完成了框架的實現,下面分享一些實現的核心要點。

AutomationE2E && Zadig

從架構上面可以看出,AutomationE2E 是我們針對音視訊場景自研的 Test Executor,底層直接基於原生的 Go Test。結合之前的經驗,我們把整套 E2E 放在 Zadig 上面。

首先在 Zadig 上面建立測試:

建立好測試之後,我們又將它關聯到了工作流上面:

接著開啟觸發器,根據一輪測試執行的大致時長來設定定時器,保障整體近似 7x24 小時無間斷:

可以看出,只是經過非常簡單的幾個步驟之後,Zadig 就為我們提供了強大的基礎保障

當測試失敗,我們可以通過 Zadig 快速下載到相關日誌,並幫助研發定位問題,體驗非常好

總的來說,我們可以通過 Zadig 的資料面板來看一下測試收益:

AutomationAPI

每個測試用例本質上是一系列 API 的組合,控制遠端虛擬裝置完成入會/離會等使用者行為。因此,AutomationAPI 本質上是一個閘道器層,用於提供遠端控制的網路通道。

AutomationAPI 主要提供 gRPC 協議介面。值得一提的是,我們基於 gRPC 的流模式來完成服務端推送,因為 APICallback 是作為非同步事件形式產生的。

AutomationBackbone

Backbone 是整個測試框架的實際後端核心,將必要的資料(例如:記錄測試產生的裝置、記錄測試的結果等等)持久化到 DB。

除此之外,Backbone 另一個核心的作用是作為中心統一管理各 Agent,在並行測試過程中根據 Agent 的負載和地理位置排程合適的 Agent 例項。

AutomationAgent Agent 是實際的工作節點,最大作用是建立虛擬裝置

虛擬裝置成本遠低於真機,一臺 32Core64GB 配置的雲主機可以模擬 100 個 VC 參會者,而如果是 100個真機參會者需要花費的成本是上百倍的。

因此,我們將支撐音視訊核心能力的 SDK 封裝成虛擬裝置,執行在雲主機上面。不同的業務產品所需要的虛擬裝置不同,我們主要支援了 RTC 虛擬裝置(應用於飛書會議)和 SIP 虛擬裝置(應用於飛書 SIP/H.323會議室聯結器)。

我們為 Agent 定義了通用的介面,由不同的虛擬裝置自身來實現這些介面,讓 Agent 能夠同時支援不同協議的虛擬裝置。

實踐經驗總結

回顧整個過程的測試工程實踐,我這裡也想總結分享一些比較容易被忽視的點。

測試穩定性

當整合測試的粒度越接近使用者真實體驗,穩定性就越容易劣化。我們在實踐過程中發現測試穩定性甚至是決定整套測試實踐生死的重要指標!相信做過整合測試的同學都有感受,整合測試很難像單元測試一樣每次執行都很穩定

我們認為只有當整合測試對業務具備強大威懾力的時候,才是整合測試最有價值的體現,即所有研發會對整合測試的失敗當做第一優先順序去處理。

那麼想要讓框架達到這一點,我們就需要不斷優化框架自身的穩定性。我們需要讓研發看到的是:測試的失敗原因絕大部分都是業務側原因,而不是測試框架自身原因。否則長久之後,測試的失敗就不會再有人關心了。

我們經過了非常長時間的優化,基本做到框架穩定性 SLA 在 99.9%:

測試並行化

測試集執行週期越短,測試覆蓋的輪次就越多,對業務的保障效果就好。那麼怎麼讓測試集執行週期足夠短呢?

我們的實踐是測試並行化。測試用例之間必須保證互相無依賴,即一個 TestCase 產生的資料不能用於另一個 TestCase 的輸入,這樣我們就可以假設測試之間可以獨立執行。

以我們在 Zadig 上面實際執行的例子來說:一共 1326 個測試用例,每個測試用例都至少執行 20s 以上,多的甚至有 80s 以上,但整體持續時間是 12m12s,這裡面就是測試並行化起到的核心作用。

測試歸因分析 當測試失敗的時候,我們希望最小化研發定位問題的額外成本。針對這一點我們主要做了兩方面的努力。

第一方面是將失敗測試進行聚類分析。(PS:這一點與音視訊業務強相關,音視訊場景下經常因為同一個原因引發大量的失敗)

第二方面是針對每個失敗的用例,快速提供日誌下載。

總結感想

以上就是我們這套測試工程實踐的關鍵思考過程和核心實現要點,由於保密原則,不方便更加細節地展開,望諒解。同時希望能夠通過我們的多年實踐,引發大家對於測試工程的深度思考,能夠結合自身業務特點產生更多有價值的實踐

Zadig,讓工程師更專注創造。

Zadig on Github
Zadig on Gitee