小程序可測性能力建設(shè)與實(shí)踐
共 10813字,需瀏覽 22分鐘
·
2024-07-30 12:16
大廠技術(shù) 高級前端 Node進(jìn)階
點(diǎn)擊上方 程序員成長指北,關(guān)注公眾號
回復(fù)1,加入高級Node交流群
本文整理自美團(tuán)技術(shù)沙龍第77期《美團(tuán)億級流量系統(tǒng)的質(zhì)量風(fēng)險(xiǎn)防控和穩(wěn)定性治理實(shí)踐》。作為一種終端產(chǎn)品生態(tài),小程序在業(yè)界產(chǎn)品中占有非常重要的地位。本文從小程序的質(zhì)量保障需求出發(fā),分析小程序的測試難點(diǎn),引出小程序可測性的基本概念,介紹美團(tuán)到店研發(fā)平臺針對小程序可測性改進(jìn)的通用化方案。最后分享美團(tuán)門票業(yè)務(wù)小程序測試工作的實(shí)踐經(jīng)驗(yàn),本文旨在為讀者在小程序質(zhì)量保障領(lǐng)域提供一些有價(jià)值的見解和啟示。
1. 引言
2. 小程序可測性介紹
2.1 使用方式與效果
2.2 接入方式
2.3 實(shí)現(xiàn)原理
3. 美團(tuán)門票業(yè)務(wù)小程序測試實(shí)踐
3.1 可測性落地
3.2 業(yè)務(wù)實(shí)踐總結(jié)
4. 總結(jié)與展望
Q&A
1. 引言
測試活動從本質(zhì)上可以視為被測系統(tǒng)因?yàn)槟硞€(gè)激勵(lì)產(chǎn)生相應(yīng)的響應(yīng),并對這些響應(yīng)進(jìn)行全面檢測的過程。這個(gè)過程(激勵(lì)->響應(yīng)->檢查)涉及到兩個(gè)角色:測試者以及測試對象,測試者執(zhí)行激勵(lì)與檢查響應(yīng),由機(jī)器(程序)或者人來完成;被測對象接受激勵(lì),產(chǎn)生響應(yīng)。從這個(gè)過程來看:激勵(lì)可控,響應(yīng)可觀,稱之為可測。以實(shí)際業(yè)務(wù)測試為例,修改緩存、網(wǎng)絡(luò)請求MCOK、頁面跳轉(zhuǎn)、用戶登錄態(tài)設(shè)置等都屬于可測性能力。
在未經(jīng)過任何可測性改進(jìn)的終端產(chǎn)品中,測試人員只能通過UI交互,從UI界面觀察來完成最基本的質(zhì)量保障。然而應(yīng)用內(nèi)部存在各種各樣復(fù)雜的邏輯、狀態(tài),要進(jìn)行更加深入的測試則需要對這些信息進(jìn)行介入與觀測。例如,在進(jìn)行打點(diǎn)測試時(shí),操作頁面后,需確認(rèn)打點(diǎn)信息是否被正常上報(bào),這一過程通常依賴網(wǎng)絡(luò)代理調(diào)試工具來完成校驗(yàn)。同樣,在用戶登錄測試環(huán)節(jié)中,登錄完成后,需要檢查緩存是否已正確記錄登錄信息,這要求具備緩存查看的能力,這些體現(xiàn)了實(shí)際業(yè)務(wù)測試場景對可測性能力的需求。
整體而言,完備地構(gòu)造出目標(biāo)場景進(jìn)行測試涉及到多個(gè)復(fù)雜的方面,同時(shí)觀測它是否符合預(yù)期也比較困難,如下圖所示。終端測試長期面臨著挑戰(zhàn)。為應(yīng)對這些挑戰(zhàn),我們以增強(qiáng)可測性為基礎(chǔ),將其貫穿測試活動的始終,使得測試能更細(xì)粒度地檢查系統(tǒng),提高測試深度和效率。
從運(yùn)行機(jī)制的角度來看,小程序的代碼邏輯運(yùn)行在宿主應(yīng)用提供的容器環(huán)境內(nèi),它無法直接控制宿主應(yīng)用本身和手機(jī)系統(tǒng),這在一定程度上增大了測試與可測性改進(jìn)的難度。
-
采用如Charles、Fiddler等網(wǎng)絡(luò)代理工具進(jìn)行HTTP/HTTPS請求和響應(yīng)的代理分析與校驗(yàn)。雖然這類工具適合進(jìn)行數(shù)據(jù)包的抓取和分析,但它們通常無法深入小程序的內(nèi)部架構(gòu),因此無法全方位控制或感知應(yīng)用的內(nèi)部狀態(tài)。 -
運(yùn)用圖像處理技術(shù)的自動化測試工具如Airtest進(jìn)行測試,它們主要關(guān)注于界面層面的操作,未能觸及應(yīng)用程序背后的邏輯處理,因此仍屬于“黑盒測試”的范疇。 -
利用微信官方提供的Minium小程序測試工具來執(zhí)行更為精細(xì)的測試操作,能夠進(jìn)行諸如API Mocking等內(nèi)部控制。然而,該方法操作復(fù)雜,并依賴于微信開發(fā)者工具,而后者與真機(jī)環(huán)境之間存在一定差異,可能影響測試結(jié)果的準(zhǔn)確性。 -
開發(fā)專用的自研調(diào)試面板用以驗(yàn)證程序邏輯和測試特定場景,但這些工具設(shè)計(jì)時(shí)常常專注于特定小程序,不易遷移至其他應(yīng)用,而且它們通常不支持自動化測試流程。
2. 小程序可測性介紹
小程序可測性的目標(biāo)在于構(gòu)建一套全方位的通用小程序可測性能力集合。該體系無縫支持真機(jī)和模擬器環(huán)境,兼容多端、多平臺,并允許不同應(yīng)用以低成本輕松接入。它能深入核心,為小程序提供全面而多元的可觀測性與可控性,覆蓋應(yīng)用界面、內(nèi)部狀態(tài)、存儲等關(guān)鍵領(lǐng)域。這一體系旨在賦能測試者更便捷地應(yīng)對復(fù)雜測試場景,顯著提高測試的效率與深入度。
| 2.1 使用方式與效果
2.1.1 手工測試
下面將以緩存管理、頁面跳轉(zhuǎn)功能為例介紹小程序在手工測試中的使用方式以及效果。
在實(shí)際的測試工作中,會結(jié)合Lyrebird使用小程序可測性,Lyrebird是美團(tuán)到店研發(fā)平臺自研的終端測試工作臺,包含終端狀態(tài)數(shù)據(jù)管理、網(wǎng)絡(luò)請求代理與Mock、缺陷記錄、自定義插件擴(kuò)展等能力。同時(shí)它還提供了圖形化操作界面,是手工與自動化測試中使用可測性能力的入口。
在小程序接入可測性能力SDK之后,可以通過可測性SDK提供的掃碼功能與Lyrebird建立連接,后續(xù)就可以通過Lyrebird在PC端利用可測性對小程序進(jìn)行控制以及觀測。
緩存管理
我們可以通過緩存管理功能驗(yàn)證依賴緩存的業(yè)務(wù)邏輯正確性,如表單信息\用戶信息暫存到緩存功能等。
-
如下圖所示,1處為緩存編輯框,展示當(dāng)前選擇設(shè)備上的小程序所有的緩存信息,并對這些緩存進(jìn)行管理,支持批量的增刪改。 -
2處展示目標(biāo)小程序的緩存變更事件信息,包括在該頁面對緩存的編輯以及小程序自身內(nèi)部對緩存的增刪改操作事件,會隨著事件的觸發(fā)實(shí)時(shí)更新。
頁面跳轉(zhuǎn)
頁面跳轉(zhuǎn)是小程序業(yè)務(wù)測試中重度使用的能力,可以利用該功能跳轉(zhuǎn)到如表單頁,商品詳情頁等中間頁面,不再需要從首頁一步一步操作進(jìn)入目標(biāo)被測頁面,減少測試前置準(zhǔn)備工作,具體可以在該Lyrebird頁面中輸入頁面路徑進(jìn)行跳轉(zhuǎn)。
2.1.2 自動化測試
將可測性能力結(jié)合Lyrebird應(yīng)用于自動化測試。如通過頁面跳轉(zhuǎn)能力直達(dá)測試場景,然后利用通過可測性錄制的頁面狀態(tài)數(shù)據(jù)進(jìn)行場景狀態(tài)還原后進(jìn)行頁面渲染,獲取頁面上的數(shù)據(jù)/布局展示,最后將實(shí)際運(yùn)行圖和預(yù)先設(shè)置好的頁面基準(zhǔn)圖進(jìn)行對比,提供渲染的差異結(jié)果,進(jìn)行視覺DIFF測試。
這類“視覺測試”以頁面為單位,通過深度鏈接跳轉(zhuǎn)技術(shù)配合一系列終端應(yīng)用本身的可測性改造,直達(dá)測試場景,并通過圖像處理技術(shù)如長圖融合、圖像增量對比和文本識別能力進(jìn)行視覺DIFF測試。
可測性建設(shè)的是對應(yīng)用內(nèi)部狀態(tài)的可觀可控能力,對于任何測試方法,只要涉及應(yīng)用內(nèi)部,可測性都能發(fā)揮重要作用。比如在健壯性測試中通過可測性構(gòu)造破壞性異常場景,或者在功能測試中模擬小程序不同的進(jìn)入方式(如二維碼、視頻號、搜索等)來測試所有可能的使用場景下小程序的運(yùn)行情況。
| 2.2 接入方式
小程序可測性能力SDK被封裝為一個(gè)NPM包,在小程序源代碼或者編譯產(chǎn)物項(xiàng)目中引入此NPM包,便可實(shí)現(xiàn)可測性能力的接入,無需進(jìn)行額外適配工作。
跨平臺運(yùn)行
除了對微信小程序的支持之外,小程序可測性能力SDK通過集成一個(gè)適配器(Adapter)將能力擴(kuò)展到多宿主應(yīng)用,包括美團(tuán)、支付寶、快手、百度等平臺的支持。這些平臺的基礎(chǔ)庫API與微信類似,適配器會根據(jù)不同平臺的特點(diǎn),對代碼進(jìn)行相應(yīng)的調(diào)整,包括基礎(chǔ)庫API、前端語法或文件類型等,以保證在各個(gè)平臺上的兼容性和一致性,實(shí)現(xiàn)跨平臺運(yùn)行。
| 2.3 實(shí)現(xiàn)原理
小程序可測性實(shí)現(xiàn)的核心思路是通過JavaScript Hook的方式,在小程序JavaScript Runtime中對如微信小程序JS基礎(chǔ)庫、業(yè)務(wù)公共基礎(chǔ)組件等目標(biāo)模塊進(jìn)行透明化介入,實(shí)現(xiàn)對其內(nèi)部的可觀可控。在此之后,通過可測性SDK內(nèi)的中控與外部建立網(wǎng)絡(luò)鏈接,從而實(shí)現(xiàn)在遠(yuǎn)端對小程序內(nèi)部狀態(tài)與功能的可觀可控。
JavaScript Hook介紹
JavaScript Hook基于JavaScript的動態(tài)特性,有以下方法:
函數(shù)Hook:直接覆蓋或修改原函數(shù):
let _originAlert = alert; // 保存原函數(shù)
alert = function () {
console.log('alert執(zhí)行開始');
_originAlert.apply(this, arguments); //執(zhí)行原函數(shù)
console.log('alert執(zhí)行結(jié)束');
}
對象屬性Hook:通過Object defineProperty定義新的或直接修改某個(gè)對象的屬性,如修改Getter/Setter方法,控制對某個(gè)對象的獲取/設(shè)置流程。
Object.defineProperty(document, 'cookie', {
set: function(val) { // 控制cookie的設(shè)置流程
console.log('獲得cookie: ', val);
currentCookie = val;
return val;
},
get: function() { // 控制cookie的獲取流程
return null;
}
});
原型鏈Hook:修改原型鏈上的數(shù)據(jù),如String、Date。
let _originalGetTime = Date.prototype.getTime; // 保存原型鏈原方法
Date.prototype.getTime = function() {
console.log('getTime has been called');
return originalGetTime.apply(this, arguments); //執(zhí)行原方法
};
Proxy對象:創(chuàng)建代理模式替代原始對象,可以重新定義獲取、設(shè)置和定義屬性等基本對象操作。
// 創(chuàng)建Proxy有兩個(gè)參數(shù):
// target:要代理的原始對象
// handler:定義哪些操作將被攔截以及如何重新定義被攔截操作的對象
let handler = {
get: function(target, prop) {
console.log(`獲取 ${prop}`);
return target[prop];
},
set: function(target, prop, val) {
console.log(`設(shè)置 ${prop} 值為 ${val}`);
target[prop] = val;
return true;
}
};
let proxy = new Proxy(window, handler);
proxy.test = 'test'; // 輸出: Setting test to test
console.log(proxy.test); // 輸出: Getting test
// test
靜態(tài)Hook:小程序構(gòu)建時(shí)在特定文件中直接修改其JavaScript源代碼。
其他方式這里就不詳細(xì)展開了。
可測性SDK的大體可分為四層:
-
通信層:與外部進(jìn)行通信,負(fù)責(zé)指令和數(shù)據(jù)與遠(yuǎn)端(如Lyrebird)的雙向流動。 -
指令分發(fā)層:對通信層接收到的參數(shù)指令進(jìn)行解析,依次調(diào)用控制小程序相關(guān)狀態(tài)的功能層模塊。 -
功能層:實(shí)現(xiàn)小程序特定功能可觀可控的業(yè)務(wù)邏輯,包括UI、網(wǎng)絡(luò)請求、存儲、應(yīng)用狀態(tài)等模塊,實(shí)現(xiàn)如請求代理與修改、切換登錄態(tài)或者控制緩存可測性功能。 -
Hook層:實(shí)現(xiàn)對實(shí)際邏輯模塊狀態(tài)和方法的透明化介入。由于小程序應(yīng)用內(nèi)部的狀態(tài)/數(shù)據(jù)與開發(fā)者代碼相關(guān)聯(lián),Hook層通過JavaScript Hook對宿主應(yīng)用基礎(chǔ)庫、公共組件、業(yè)務(wù)特定邏輯三種類型的功能模塊進(jìn)行攔截介入,使得其狀態(tài)/數(shù)據(jù)可觀和可控,為功能層提供實(shí)現(xiàn)基礎(chǔ)。Hook層一般需要先于業(yè)務(wù)代碼加載,保證攔截的有效性。 -
宿主應(yīng)用基礎(chǔ)庫。通用性改造,對小程序容器提供的系統(tǒng)級接口進(jìn)行介入,如網(wǎng)絡(luò)請求、地理信息等。 -
公共組件。組件級通用,如美團(tuán)的公共登錄組件,對其進(jìn)行改造后,接入登錄組件的小程序都能夠使用相應(yīng)的可測性能力,比如切換登錄態(tài)/模擬登出等能力。 -
業(yè)務(wù)特定邏輯。某個(gè)小程序特有的業(yè)務(wù)邏輯,通過可測性SDK提供的API對這些邏輯進(jìn)行改造后以插件形式集成定制化能力。
下面將以網(wǎng)絡(luò)請求可觀可控為例介紹小程序可測性的實(shí)現(xiàn)原理。
網(wǎng)絡(luò)請求代理
當(dāng)外部希望控制小程序設(shè)置網(wǎng)絡(luò)代理時(shí),整體流程如下:
-
外部(人/機(jī)器)首先通過HTTP/WebSocket方式傳遞包含設(shè)置小程序請求代理的指令,如圖即攔截小程序發(fā)送的請轉(zhuǎn)發(fā)到127.0.0.1:1234代理服務(wù)器;
-
可測性SDK在通信層接收相應(yīng)的指令后。將其傳遞給指令分發(fā)層。在指令分發(fā)層中,收到指令后進(jìn)行解析,并按預(yù)定規(guī)則對指令執(zhí)行進(jìn)行編排,確定執(zhí)行順序;
-
指令分發(fā)層按編排順序調(diào)用功能層設(shè)置網(wǎng)絡(luò)代理并傳入開啟狀態(tài)和代理服務(wù)器地址參數(shù),功能層通過修改這兩個(gè)變量,控制Hook層對請求API的攔截,從而改變請求代理的狀態(tài);
-
Hook層攔截微信基礎(chǔ)庫里wx對象的request方法,如下圖代碼所示,分為以下流程
3. 美團(tuán)門票業(yè)務(wù)小程序測試實(shí)踐
| 3.1 可測性落地
下面通過門票業(yè)務(wù)一個(gè)具體的新需求測試?yán)觼斫榻B可測性如何在測試活動中進(jìn)行落地。
需求背景
用戶從商品詳情頁進(jìn)入到填單頁,在選擇日期、數(shù)量或填寫游玩人等信息后,為了減少用戶的操作,再次進(jìn)入該填單頁需要保持之前填寫的信息不變。
操作路徑劃分
該過程需要經(jīng)過以下步驟:進(jìn)入填單頁 —> 打開價(jià)格日歷彈層,選擇相應(yīng)的日期 —> 添加數(shù)量 —> 填寫或者選擇游玩人 —> 點(diǎn)擊返回退出填單頁 —> 再次進(jìn)入填單頁,查看它當(dāng)前的狀態(tài)。我們選擇對緩存進(jìn)行可測性改進(jìn),依靠指令數(shù)據(jù)驅(qū)動+內(nèi)部方法調(diào)用來達(dá)到同等UI操作的效果,保障此類場景測試的穩(wěn)定性并提高執(zhí)行效率。
技術(shù)實(shí)現(xiàn)
整體通過緩存實(shí)現(xiàn)。在進(jìn)入填單頁時(shí),首先會讀取小程序上的緩存并渲染;在選擇日期、數(shù)量和游玩人時(shí),分別對相關(guān)信息進(jìn)行暫存;在退出填單頁時(shí),將這些暫存的數(shù)據(jù)寫入緩存。
測試分析
由于進(jìn)入填單頁需要讀取緩存進(jìn)行渲染,因此測試過程中首先應(yīng)從UI上進(jìn)行驗(yàn)證,判斷第二次進(jìn)入的日期、數(shù)量和游玩人是否與上一次進(jìn)入時(shí)選擇的狀態(tài)一致;其次還應(yīng)從數(shù)據(jù)上進(jìn)行驗(yàn)證,即進(jìn)入填單頁有“讀”緩存的動作;在退出填單頁時(shí),需要將暫存的數(shù)據(jù)寫入緩存,因此測試過程中應(yīng)驗(yàn)證數(shù)據(jù)能正確地寫入緩存,而且緩存里有正確的值。
可測性能力實(shí)踐落地
-
通過可觀校驗(yàn)“寫”的正確性。對于“寫”,驗(yàn)證緩存的寫入動作,并且寫入緩存的數(shù)據(jù)是正確的。緩存的可觀性改造能夠?qū)ⅰ皩憽钡膭幼鳌ⅰ皩憽钡漠?dāng)前值以及當(dāng)前緩存具體信息,進(jìn)行上報(bào),這樣就可以自動化校驗(yàn)當(dāng)前操作后是否緩存值是否發(fā)生了正確的變化,以此完成對緩存“寫”的校驗(yàn)。
-
通過可控校驗(yàn)“讀”的正確性。對于“讀”,首先驗(yàn)證UI能夠正確展示,其次從數(shù)據(jù)上驗(yàn)證有緩存的“讀”動作。由于測試緩存必須經(jīng)歷選擇日期、選擇數(shù)量、選擇游玩人,返回退出填單頁等多個(gè)步驟。測試路徑較為繁瑣,因此,對緩存的可控性改造后,傳入相應(yīng)的配置指令(如2.2部分介紹),控制緩存中的數(shù)據(jù),直達(dá)被測頁面和狀態(tài),并通過自動化測試比對當(dāng)前運(yùn)行的頁面和頁面基準(zhǔn)圖,判斷它是否正確被渲染,以此分別從數(shù)據(jù)和UI上完成對緩存“讀”的校驗(yàn)。
門票業(yè)務(wù)在小程序測試上目前已經(jīng)落地多種可測性能力,如下圖所示,包括控制頁面跳轉(zhuǎn)、請求代理、控制登錄、日志上報(bào)、隱私治理、前后端環(huán)境、錄制回放、自動化交互控制等都在門票測試活動中有相應(yīng)的落地,發(fā)揮著非常重要的作用。
| 3.2 業(yè)務(wù)實(shí)踐總結(jié)
4. 總結(jié)與展望
Q&A
A:代理邏輯本身很簡單,出錯(cuò)概率不大。進(jìn)行Hook時(shí),會有異常監(jiān)控能力以及相應(yīng)的兜底策略,即使出問題,也盡量降低對業(yè)務(wù)實(shí)際使用的影響。
Q:可測性SDK需要對業(yè)務(wù)代碼進(jìn)行改造嗎?
Q:Lyrebird項(xiàng)目和小程序可測性SDK的關(guān)系是什么?
A:Lyrebird與小程序可測性是兩個(gè)獨(dú)立的項(xiàng)目。小程序可測性SDK是以一個(gè)NPM包的形式實(shí)現(xiàn)的,在小程序里安裝NPM包,即可使小程序具有可測性。Lyrebird可以與小程序可測性SDK的通信接口進(jìn)行連接,然后用戶可通過Lyrebird中小程序可測性頁面使用小程序可測性能力。
Q:針對小程序可測試性能力建設(shè)與實(shí)踐,我想問下,如果我們要用你們的測試工具,需要做什么適配嗎?
A:不需要進(jìn)行額外適配,最終的呈現(xiàn)會是NPM包形式,在產(chǎn)物里安裝就可以接入我們的可測性能力,可以對它進(jìn)行控制。
Q:生產(chǎn)環(huán)境會接入可觀測SDK嗎?如果接入對性能有多大影響?
A:首先是對它的性能的影響,我們實(shí)際上是對小程序里的基礎(chǔ)庫的API或者一些狀態(tài)數(shù)據(jù)進(jìn)行了攔截,會對性能產(chǎn)生一定的影響,但目前這個(gè)影響范圍對業(yè)務(wù)來說比較小,是可接受的。生產(chǎn)環(huán)境的不會引入可測性SDK,因此不會對線上質(zhì)量造成影響。
Q:小程序可測性有不適合使用的場景?
---------- END ----------
Node 社群
我組建了一個(gè)氛圍特別好的 Node.js 社群,里面有很多 Node.js小伙伴,如果你對Node.js學(xué)習(xí)感興趣的話(后續(xù)有計(jì)劃也可以),我們可以一起進(jìn)行Node.js相關(guān)的交流、學(xué)習(xí)、共建。下方加 考拉 好友回復(fù)「Node」即可。
“分享、點(diǎn)贊、在看” 支持一波??
