引言
“測完了嗎?” 是系統測試崗位同學經常被問到的問題,提問的人可能是合作的研發, 合作的產品經理,甚至是專案的業務方,也有可能是測試自己。
這個問題至少有兩層意思,不僅問新功能測試進度是否完成,更重要的是想知道測試的結果怎麼樣,測試同學如何回答這個問題,背後反映出來的是對本次測試工作的信心。
軟體工程理論認為,受限於時間、資源、外部輸入、測試人員經驗等主客觀原因,對一個系統完全測試是不可能的, 但是也正是由於上面的原因,導致了不同的測試人員或者團隊,在執行測試的效果上參差不齊。但是作為有追求的測試人員,我們要努力靠近 “完全的測試”。
本文基於申通的業務和技術現狀,申通技術質量團隊嘗試回顧專案測試的全過程,從測試設計,新功能測試,迴歸等方面給出自己的答案。
01 準備工作
在正式開始之前,請允許我花一些時間介紹一下申通技術質量的工作模式。
在軟體專案管理中,對質量的關注部分往往放在用例的完成情況以及缺陷的修復情況等結果方面,從一些常見的專案管理工具,如 jira、teambition 等產品設計上也有所體現。
但是為了回答本文問題,光靠這些結果是不夠的,因為關鍵的用例設計,測試執行過程往往缺乏標準化,導致結果的可信度大打折扣。因此,我們需要對測試過程做精細化的管理。從實際情況出發,目前我們著眼在最常見也是最重要的功能測試方面。
我們對常見的專案測試過程進行了抽象,從測試設計、新功能測試、迴歸等方面進行了標準細化,並且自研了一套 “質量管家” 系統,實現了測試工作流的線上化。不同於市面上的專案管理工具,質量管家在 “工具” 的基礎上,融入了流程標準的概念。除了在測試過程中給測試同學提供幫助之外,還可以對測試過程進行標準化管理。
比如我們透過設定了一些測試流水線,對不同型別的專案需求測試進行了流程規範,確保關鍵的測試動作執行到位,同時也透過比如測試評審紀要功能,對評審待辦事項進行自動跟蹤,避免待辦被遺忘,測試完成自動傳送報告,節省測試同學書面工作時間。
產品示意:
得益於質量管家實現的過程量化,我們具備了回答 “測完了嗎?” 問題的資料基礎能力,可以基於此做質量過程和結果量化。 下文我們從幾個關鍵點展開論述。
02 人工測試有效性
雖然自動化測試是很多測試團隊追求的方向,但是從申通的產品特性出發,綜合考慮測試 ROI,傳統手工測試(人工測試)還是佔據了絕大多數的時間。所以我們把重點放在人工執行的功能測試,其中的幾個關鍵點,包括了用例設計完整性,新功能測試完整性,迴歸充分性,以及對上述環節的不斷最佳化迭代。
更多內容可以學習《測試工程師 Python 工具開發實戰》書籍、《大話效能測試 JMeter 實戰》書籍
2.1 用例設計
傳統的測試用例設計,基於經典的軟體工程理論,大致上包含 8 要素:用例編號、所屬模組、測試標題、重要級別、前置條件、測試輸入、操作步驟、預期結果。 規範的測試用例通常會用一個表格的形式來展現,我相信很多從事軟體測試時間比較久的同學都經歷過。
經典的實踐結合測試用例設計理論(等價類,邊界值等)可以一定程度上確保測試用例設計的完整性,但這是前網際網路時代的經驗。在當前我們很多時候要求快速迭代,快速上線;技術團隊,包括測試,沒有辦法在前置的書面分析工作上投入足夠的時間,加上很多測試團隊沒有在測試用例方面下功夫做管理,於是很多網際網路技術團隊的測試用例就簡化到了一句話,甚至沒有大綱。
這樣導致的結果就是,很多測試需要關注的細節,由於開始沒有被書面記錄到用例中,導致真正在測試執行的過程裡,用例執行憑感覺,缺陷發現看經驗,甚至看運氣,很多經典測試中好的實踐被拋棄,導致測試遺漏的問題常常出現。
那麼如何平衡完整性和效率之間的關係,更好地適應網際網路的開發模式?經過思考,我們吸收了部分經典實踐中的關鍵部分,摒棄了一些無關緊要的部分,形成測試 用例模版; 比如用例步驟和預期結果,以及正常、異常、以及非功能用例,在用例設計環節作為約束,最大程度上保證用例設計全面,同時結合工具進行用例編寫提效,最後透過匯入質量管家實現用例線上化。
根據不同的業務,在質量管家上面可以設定不同的模板,在經典實踐的基礎上,可以附加業務特性,比如資金專項,相容性專項等,以滿足不同的測試需要。
整體的用例編寫基於 xmind,適應當前很多測試同學的習慣,同時也比 Word,Excel 的編寫效率要高。
用例匯入之後可以線上修改,檢視和執行,保證用例執行過程留痕。
同時用例還支援一鍵轉回歸用例,減少用例用完即拋造成的浪費,有利於測試經驗沉澱。
2.2 程式碼覆蓋
用例設計完成,研發提測之後,就要開始執行。這一部分我們重點關注程式碼測試覆蓋度。
為什麼要看程式碼覆蓋度,它可以直觀地反映這次測了多少程式碼,有多少沒有被測試,我們知道,程式碼覆蓋 100%,測試可能也不完整,但是程式碼覆蓋面不到 100%,測試肯定不完整。 很長一段時間,我們的測試程式碼覆蓋面是個黑盒,從抽樣結果和歷史線上問題來看,這部分存在很大的漏洞。
度量程式碼覆蓋技術已經有比較久的歷史,以往通常是應用在單元測試等自動化測試環節,用來度量自動化測試的有效性。業界開源的,或者基於開源技術二次開發的技術也比較多。我們採用的同樣也是基於 jacoco 的技術二次開發申通自己的覆蓋率度量外掛,並且基於此配備了一整套的程式碼覆蓋率度量底座(SCC)。
原生的 jacoco 和單元測試配合比較好,如果要應用在更大範圍的專案測試上,還存在一些問題需要解決。一些關鍵的對比如下。(綠色部分為原生支援,紅色部分為不支援)
關鍵問題 1:資料持久化
原生 jacoco 的資料儲存在被測伺服器上,在雲原生的情況下,一旦應用重新構建和部署,相關的資料也隨之消失,同時也存在容器重建、遷移等情況導致資料丟失。
由於自動化測試持續的時間比較短,測試中一般不會存在上述情況導致的資料丟失的情況,即便丟失了,重跑自動化測試的成本也比較小(這也是自動化測試的優勢)。
但是在人工測試的情況下, 測試周期需要持續數天甚至更長的時間的,而且由於缺陷修復,程式碼提交等情況,一定會出現被測服務重新部署的情況。資料丟失之後,大多也不能為了跑覆蓋率資料進行重複測試,這樣資料可靠的持久化就變成了剛需。
這個問題的解決方案如下:
完成覆蓋率外掛的接入之後,測試人員無需做更多的關注,正常執行測試即可。在測試的過程中, 測試覆蓋率的資料持續被生產並且儲存在被測伺服器上。
當應用重新部署的時候,SCC 叢集啟動任務,下發命令去對應的被測伺服器上 dump 相關的測試覆蓋率資料。完成之後在 SCC 上完成覆蓋率的聚合計算。
完成覆蓋率計算之後, 上傳到檔案儲存服務上,供後續使用。
關鍵問題 2:類衝突程式碼清零問題
原生的 jacoco 存在一個比較嚴重的問題, 就是在多個分支同時部署的時候,在流水線上會合併為 release 分支,本質上 jacoco agent 的計算的是 release 的覆蓋率,假如被測分支 feature1 修改了 classA,並且此時測試已經完成了 classA 中的全部測試覆蓋,如果此時同樣部署在測試環境的分支 featureB,同樣往 classA 提交了程式碼,會導致原本已經測試完成完成的 featureA 中的 classA 的覆蓋率被清零。
如下圖,其中綠色部分的是測試需要負責的專案,黃色部分是測試未參與的其他分支。
這個問題的影響是,如果被測分支中大量的測試工作已經完成,並且發生衝突的類新增程式碼(需要重點測試)比較多的話,會導致覆蓋率資料會大幅度下降。因此我們也投入大量時間是花了大量的嘗試解決此問題。
從 jacoco 的設計來看, 一個類中的一行程式碼 發生變更,就意味著這個類需要重新測試,有一定的合理性。但是如果按此原則,實際在專案過程中落地存在困難。我們的解決方向是把 “衝突清零” 的範圍控制到方法層面,也比較符合實際情況。
技術方案如下:在儲存原始覆蓋率資料的同時,將需要把覆蓋率資料依據方法維度進行切割,在計算的時候,按照方法維度做清零計算,避免整個類的覆蓋率被清零。
專案測試落地應用:
有了比較可靠的覆蓋率統計方案之後,還需要處理一些在實際應用中的問題,才能實際在專案測試中發揮作用,最典型的問題是有些程式碼透過常規的測試手段無法覆蓋,或者沒有必要覆蓋的情況,對於這些情況,我們在覆蓋率報告的基礎上,於質量管家中增加了覆蓋率分析的節點,要求測試人員對為覆蓋的程式碼進行標註說明,進一步防止漏測情況的發生, 同時對於一些沒有測試必要的程式碼,比如列印日誌等,做了排除處理,以免影響最終的測試透過性檢查。
報告彙總
未覆蓋分析標註
研發自測有效性管控:
在實際的研發工作中,由於一些客觀原因,很多需求其實沒有經過測試團隊測試驗收, 都是由研發自測之後完成上線,很長一段時間,質量部門對研發自測的關注或者是管控的力度較弱,可能是缺乏相關的流程規範,或者是有流程規範,但是落地效果無法把握。
由於上述原因,自測導致的線上問題佔比也比較高。
之前的一系列測試能力建設加上覆蓋率度量的能力,我們現在有能力科學的對研發自測的質量有一個客觀的評估。
整套方案上儘可能做到了對研發過程的少打擾,透過綜合單元測試、 自動化測試、以及研發或者產品自測的結果資料,產出融合覆蓋率,避免單一維度的測試覆蓋率導致的不客觀問題。這套方案也幫助開發在無測試幫助的情況下,對自己的釋出質量有了一定的底氣。
落地效果:提升測試覆蓋面
當前覆蓋率系統,每天計算產出覆蓋率報告 100 份以上。
2023 年的測試任務中,有 8 成以上需求的程式碼測試覆蓋率都超過了 80% 以上, 有效減少了線上問題漏測的情況,而且透過對程式碼覆蓋率的關注,大大提升了測試團隊的白盒測試能力,幫助發現業務邏輯漏測,後門程式碼,無效分支等各種異常。
線上問題中,由於測試不完全導致的線上問題,整體降低 50% 以上。
03 迴歸與精準測試
3.1 背景
出於測試成本考慮,覆蓋率上我們主要關注增量覆蓋率,這樣就有另外一個問題沒有解決, 一些增量的程式碼對原有程式碼的影響, 其實是沒有能力反映出來的。這類問題也是線上比較常見,但也是比較難以透過測試發現的。這需要我們思考其他的解決方案。
3.2 思路
常規的思路一般有兩種:
1.透過投入大量時間做全面的迴歸,大水漫灌式的做法, 我們也嘗試過類似的實踐,這樣的方案對於產品規模較小的業務比較合適,比如功能比較單一的 APP,但是如果涉及到一個全鏈路的複雜系統,這樣的迴歸方案變得很難落地。
2.透過自動化的方式,儘量覆蓋更多的程式碼邏輯,透過高效的自動化方式進行迴歸。 但是在實際的生產中,自動化用例往往不太成熟,無法實現有效地迴歸覆蓋。當然有些公司的自動化建設比較成熟,但是帶來的其他問題是自動化的維護成本和執行成本高企。
上述兩種方式在申通不同的業務上也有實踐,在此的基礎上,我們產出了另外一套精準測試的方案,期望能夠準確識別變更的影響面,做到迴歸測試有的放矢,給人工迴歸,和自動化迴歸提供有效支撐。
要達到這一目標,解決方案中至少要具備兩部分能力:
1.識別影響: 基於變更識別關聯影響(影響了什麼?)
2.測試評估: 基於影響識別測試範圍(測什麼?)
對於第一部分,以最常見的業務邏輯程式碼變更舉例,常規有兩種做法:
動態方法: 採取如 java 位元組碼技術,透過動態收集程式碼執行時的呼叫關係,建立程式碼之間的呼叫鏈,這樣的方法好處是隻要採集的資料足夠全,得到的呼叫鏈相對比較真實,可以遮蔽一些無效的呼叫,產出的都是真實發生的呼叫關係,缺點就是技術成本高,包括接入、採集、儲存和計算。
靜態方法: 業界有一些開源的解決方案,如 java-callgraph,這樣的技術好處是技術成本較低,能夠透過靜態掃描的方式,短時間內得到程式碼之間的呼叫關係,缺點是給出的資料顆粒度往往比較粗,需要對開源包進行二次開發來真正達到準確識別變更所影響的呼叫入口的效果。
基於綜合成本考慮,申通採用靜態方法,結合開源能力做了二次開發解決了在外掛部署的效率問題,以及結合研發流水線實現影響面自動測算,我們可以透過對被測程式碼進行靜態掃描,產出一次變更所關聯的所有入口。
透過對變更的分析,得到被影響的程式碼入口,也基本得到了測試入口。
第二部分,基於影響識別測試範圍。這一部分的解決方案需要提前建立測試用例和程式碼之間的關聯關係,並準備一套 “錄製系統”,基於錄製系統,測試人員一條條的執行用例,系統後臺記錄在用例執行過程中所經過的程式碼,以此來建立用例和程式碼之間的關係。這樣的做法可以建立比較精準的關聯關係,不足是維護的成本巨大,以申通舉例, 上萬條測試用例,一條條的透過錄制回放的關係,會耗費大量的時間,等一輪關係建立完成之後,可能系統又發生了較大的變化,導致所有的關係都要重來。在目前的情況下,這樣的成本無法接受。
我們需要解決成本的問題, 經過思考,我們決定僅從測試用例入手建立到服務層的關係,這樣可以避免底層業務邏輯程式碼變更帶來的關係維護成本,同時在建立關係的時候也可以比較快速地完成。
方案示意如下
對於人工測試:
1.對頁面測試的人工用例(用例集合),我們先透過手工繫結的方式,建立人工用例和頁面的關係。
2.然後在對應的頁面中,透過抓包的方式,全量的抓取該頁面所呼叫的後臺服務。
3.然後反過來,我們就得到了用例 + 頁面 +API 之間的關係圖譜。
對於自動化用例:
相對來說比較容易,透過靜態分析的方式,可以自動得出自動化用例所呼叫的後臺服務。也就建立了自動化用例 +API 的關係圖譜。
完成結合:
第一部分的能力,使得我們透過變更的程式碼,可以得到影響的 API, 透過影響的 API 可以得到相關的用例,包含自動化和手工部分。
在實際的測試過程中,測試人員只需要輸入對應分支,後臺就可以推薦出對應用例,實現精準的範圍評估和迴歸測試。
3.3 擴充套件應用:
由於識別影響和測試評估的能力是互相獨立的, 嚴格來說,識別能力作為能力單獨對外提供服務。
比如識別到某次變更影響的入口之後,發現相關的入口沒有自動化用例或者人工用例後,可以自動生產待辦任務,督促相關測試完成用例補充。
又比如在 Code Review 的環節,可以提供更多的輸入給程式碼稽核人,做更加全面的程式碼審查等等。
還有一些定製化的應用,比如某些介面協議發生變更的情況下,可能要觸發對應的前端或者依賴方的迴歸測試。
基於這些能力,可以進一步的提升測試的完整性。
04 自動化測試有效性
申通技術部現在有上萬的自動化用例每天在執行,自動化的應用滲透在從提測到線上巡檢的各個環節。如何保證這些自動化用例能發揮效果,是一個需要關注的問題。
常規的做法是,從手工的用例出發選取一些關鍵的業務用例進行自動化實現,申通也有類似實踐,相比有些公司有專門的自動化測試工程師來負責此工作,在申通並沒有如此細緻的分工,同時手工用例編寫的細緻程度,以及選取要實現自動化的用例存在很大成分的人為判斷因素,導致在所謂核心用例的覆蓋面的基礎上,無法提供更多有效的支撐來進行自動化用例建設。我們的做法除了從用例出發,還會從以下幾個方面關注。
4.1 介面覆蓋
顧名思義,就是從應用介面看那些需要實現自動化的服務。第一個要解決的問題是介面列表從哪裡來,與一些大廠可能有比較完整規範的介面文件,服務序號產生器制來識別服務列表不同,在現有的條件下,申通是透過線上監控的資料來拉取服務列表。
從監控平臺拉取的資料除了有服務地址之外,還有服務呼叫量等資訊,透過這些資訊,結合業務重要性的綜合判斷,我們在全量的服務列表基礎上可以對服務進行分級,那麼介面自動化目標也就有了優先順序,基於這些優先順序去進行服務自動化覆蓋就變得有的放矢。
4.2 程式碼覆蓋
上文提到了我們有一套程式碼覆蓋率度量的基礎能力(SCC), 基於此能力,我們可以衡量出在自動化集中執行期間的程式碼全量覆蓋率,藉此可以對自動化的有效性和介面覆蓋的層面上更加深入。
4.3 場景覆蓋
場景是什麼,往往是基於業務的描述,在測試方面可以抽象為外部呼叫進入到系統的不同入參組合,以及這些入參所經過程式碼呼叫鏈路,那麼基本可以認為場景是入參決定的;簡化來說,我們可以認為是經典的 “等價類”,“邊界值” 的實際生產應用。不同於 “設計” 各種測試用例, 在場景覆蓋的命題下,我們更多是透過獲取線上資料來進行有效的組合形成不同的自動化場景用例,所謂 “有效組合”,是指的我們基本不會去臆造一些實際生產中不存在的資料,這樣的做法更加貼近實際,同時也保障技術資源不會被浪費。
對於場景自動化的落地,大廠的做法可能是透過引流或者是鏈路分析來識別,需要較大的資料儲存和計算成本,申通的做法成本更低一些, 透過線上資料完成各種場景的組裝之後,將被測系統的業務抽象為流程(相對於單介面)自動化用例,透過類似資料驅動的方式,輸入到流程用例中,完成業務系統的場景自動化覆蓋。
4.4 問題反饋
上述的做法都是問題事前的方法, 對於事後的方法判斷測試有效性主要是透過線上問題的反饋來回溯驗證,這部分下文展開。
05 基於問題做最佳化
申通技術團隊,已經完成了將原 “技術支援” 團隊升級為 “技術服務” 團隊,在更加規範化地給使用者處理產品使用上的問題過程中,積累了大量的服務資料,其中一部分就是產品線上問題和建議。
現在技術服務團隊基本上涵蓋了申通技術部提供的所有產品和系統,相關的線上問題都可以得到比較及時和完整的收集。 基於這些線上缺陷,技術團隊可以回過頭去看在研發測試過程中,出現了哪些遺漏,比如是否測覆蓋率不足,是否迴歸不全面等等。研發,測試,上線,服務四個環節有機協同,給系統最佳化提供方向,形成 PDCA 良性迴圈。
技術服務補全了從研發到上線的質量體系
06 未來計劃
上述的一系列措施,便是現在申通測試如何回答 “測完了沒?” 這個問題的答案,當然測試的範圍非常廣,我們只是基於現階段的業務特點和技術質量要求,把重點放在了功能測試層面,對於非功能測試領域的關注還是相對較少。
對於未來我們計劃在下面的幾個方面進行一些探索。
6.1 前端程式碼覆蓋率識別
對於覆蓋率,目前我們能識別後端程式碼的測試覆蓋率,對於前端程式碼的測試覆蓋率,需要和前端研發團隊深入合作,制定標準,透過埋點等定製化的技術方案來實現。
6.2 資料,配置變更影響識別
對於精準測試,目前我們的關注點放在了後端程式碼的變更上,未來還可以透過識別前端程式碼變更,資料結構變更,配置變更的影響來擴充套件更多的應用場景和訪問,使得質量風險的評估更加全面。
6.3 AI 測試助手
AI 的應用,尤其是生成式的大模型,在各領域都有不錯的實踐,在技術方面,之前我們有看到 AI 程式設計,AI 做程式碼掃描的實踐,對實際的工作也是非常有幫助,在質量領域方面,AI 至少可以在測試分析,自動化測試,程式碼缺陷分析方面做一些有效的輔助。
基於現在的 “小模型” 技術,我們可以用更低成本對模型進行部署和訓練,基於申通現有的質量要求以及歷史上的質量資料,訓練出更加貼近申通業務的質量 AI。
更多內容可以學習《測試工程師 Python 工具開發實戰》書籍、《大話效能測試 JMeter 實戰》書籍