溫州溫州市詳解小程序自動(dòng)化測(cè)試
閱讀 85972 · 發(fā)布日期 2020-08-24 17:26 · 溫州優(yōu)光網(wǎng)絡(luò)科技有限公司|建站|APP小程序制作|做網(wǎng)站SEO推廣優(yōu)化
【摘要】
【相關(guān)學(xué)習(xí)推薦:微信小程序教程】背景近期團(tuán)隊(duì)打算做一個(gè)小程序自動(dòng)化測(cè)試的工具,期望能夠做到業(yè)務(wù)人員操作一遍小程序后,自動(dòng)還原之前的操作路徑,并且捕獲操作過(guò)程中發(fā)生的異常,以此來(lái)判斷這次發(fā)布是否會(huì)影響小程序的基礎(chǔ)功能。上述描述看似簡(jiǎn)單,但是中間還是有些難點(diǎn)的,第一個(gè)難點(diǎn)就是如何在業(yè)務(wù)人員操作小程序的時(shí)候記錄操作路徑,第二... 【溫州小程序開(kāi)發(fā),溫州微信公眾號(hào),平陽(yáng)做網(wǎng)站,平陽(yáng)網(wǎng)站建設(shè)公司,平陽(yáng)小程序商城制作,昆陽(yáng)萬(wàn)全做網(wǎng)站,鰲江水頭小程序,蕭江騰蛟微信公眾號(hào),山門順溪南雁海西南麂鳳臥麻步懷溪網(wǎng)絡(luò)網(wǎng)店服務(wù),政采云網(wǎng)店管理服務(wù)】...
【相關(guān)學(xué)習(xí)推薦:
微信小程序教程】背景近期團(tuán)隊(duì)打算做一個(gè)小程序自動(dòng)化測(cè)試的工具,期望能夠做到業(yè)務(wù)人員操作一遍小程序后,自動(dòng)還原之前的操作路徑,并且捕獲操作過(guò)程中發(fā)生的異常,以此來(lái)判斷這次發(fā)布是否會(huì)影響小程序的基礎(chǔ)功能。
上述描述看似簡(jiǎn)單,但是中間還是有些難點(diǎn)的,第一個(gè)難點(diǎn)就是如何在業(yè)務(wù)人員操作小程序的時(shí)候記錄操作路徑,第二個(gè)難點(diǎn)就是如何將記錄的操作路徑進(jìn)行還原。
自動(dòng)化 SDK如何將操作路徑還原這個(gè)問(wèn)題,首選官方提供的 SDK:
miniprogram-automator。
小程序自動(dòng)化 SDK 為開(kāi)發(fā)者提供了一套通過(guò)外部腳本操控小程序的方案,從而實(shí)現(xiàn)小程序自動(dòng)化測(cè)試的目的。
通過(guò)該 SDK,你可以做到以下事情:
控制小程序跳轉(zhuǎn)到指定頁(yè)面獲取小程序頁(yè)面數(shù)據(jù)獲取小程序頁(yè)面元素狀態(tài)觸發(fā)小程序元素綁定事件往 AppService 注入代碼片段調(diào)用 wx 對(duì)象上任意接口...上面的描述都來(lái)自官方文檔,建議閱讀后面內(nèi)容之前可以先看看官方文檔,當(dāng)然如果之前用過(guò) puppeteer ,也可以快速上手,api 基本一致。
下面簡(jiǎn)單介紹下 SDK 的使用方式。
// 引入sdkconst automator = require('
miniprogram-automator'
)// 啟動(dòng)微信開(kāi)發(fā)者工具automator.launch({
// 微信開(kāi)發(fā)者工具安裝路徑下的 cli 工具 // Windows下為安裝路徑下的 cli.bat // MacOS下為安裝路徑下的 cli cliPath: '
path/to/cli'
, // 項(xiàng)目地址,即要運(yùn)行的小程序的路徑 projectPath: '
path/to/project'
, }
).then(async miniProgram => {
// miniProgram 為 IDE 啟動(dòng)后的實(shí)例 // 啟動(dòng)小程序里的 index 頁(yè)面 const page = await miniProgram.reLaunch('
/page/index/index'
) // 等待 500 ms await page.waitFor(500) // 獲取頁(yè)面元素 const element = await page.$('
.main-btn'
) // 點(diǎn)擊元素 await element.tap() // 關(guān)閉 IDE await miniProgram.close() }
)復(fù)制代碼有個(gè)地方需要提醒一下:
使用 SDK 之前需要開(kāi)啟開(kāi)發(fā)者工具的服務(wù)端口,要不然會(huì)啟動(dòng)失敗。
捕獲用戶行為有了還原操作路徑的辦法,接下來(lái)就要解決記錄操作路徑的難題了。
在小程序中,并不能像 web 中通過(guò)事件冒泡的方式在 window 中捕獲所有的事件,好在小程序所以的頁(yè)面和組件都必須通過(guò) Page 、Component 方法來(lái)包裝,所以我們可以改寫這兩個(gè)方法,攔截傳入的方法,并判斷第一個(gè)參數(shù)是否為 event 對(duì)象,以此來(lái)捕獲所有的事件。
// 暫存原生方法const originPage = Pageconst originComponent = Component// 改寫 PagePage = (params) => {
const names = Object.keys(params) for (const name of names) {
// 進(jìn)行方法攔截 if (typeof obj[name] === '
function'
) {
params[name] = hookMethod(name, params[name], false) }
}
originPage(params) }
// 改寫 ComponentComponent = (params) => {
if (params.methods) {
const {
methods }
= params const names = Object.keys(methods) for (const name of names) {
// 進(jìn)行方法攔截 if (typeof methods[name] === '
function'
) {
methods[name] = hookMethod(name, methods[name], true) }
}
}
originComponent(params) }
const hookMethod = (name, method, isComponent) => {
return function(...args) {
const [evt] = args // 取出第一個(gè)參數(shù) // 判斷是否為 event 對(duì)象 if (evt && evt.target && evt.type) {
// 記錄用戶行為 }
return method.apply(this, args) }
}
復(fù)制代碼這里的代碼只是代理了所有的事件方法,并不能用來(lái)還原用戶的行為,要還原用戶行為還必須知道該事件類型是否是需要的,比如點(diǎn)擊、長(zhǎng)按、輸入。
const evtTypes = [ '
tap'
, // 點(diǎn)擊 '
input'
, // 輸入 '
confirm'
, // 回車 '
longpress'
// 長(zhǎng)按]const hookMethod = (name, method) => {
return function(...args) {
const [evt] = args // 取出第一個(gè)參數(shù) // 判斷是否為 event 對(duì)象 if ( evt && evt.target && evt.type && evtTypes.includes(evt.type) // 判斷事件類型 ) {
// 記錄用戶行為 }
return method.apply(this, args) }
}
復(fù)制代碼確定事件類型之后,還需要明確點(diǎn)擊的元素到底是哪個(gè),但是小程序里面比較坑的地方就是,event 對(duì)象的 target 屬性中,并沒(méi)有元素的類名,但是可以獲取元素的 dataset。
為了準(zhǔn)確的獲取元素,我們需要在構(gòu)建中增加一個(gè)步驟,修改 wxml 文件,將所有元素的 class 屬性復(fù)制一份到 data-className 中。
{
text}
}
.toast-close'
) element.tap() // Error!// 必須先通過(guò)自定義組件的 tagName 找到自定義組件// 再?gòu)淖远x組件中通過(guò) className 查找對(duì)應(yīng)元素const element = await page.$('
toast .toast-close'
) element.tap()復(fù)制代碼所以我們?cè)跇?gòu)建操作的時(shí)候,還需要為元素插入 tagName。
// 記錄用戶行為的數(shù)組const actions = [];
// 添加用戶行為const addAction = (type, query, value = '
'
) => {
actions.push({
time: Date.now(), type, query, value }
) }
// 代理事件方法const hookMethod = (name, method, isComponent) => {
return function(...args) {
const [evt] = args // 取出第一個(gè)參數(shù) // 判斷是否為 event 對(duì)象 if ( evt && evt.target && evt.type && evtTypes.includes(evt.type) // 判斷事件類型 ) {
const {
type, target, detail }
= evt const {
id, dataset = {
}
}
= target const {
className = '
'
}
= dataset const {
value = '
'
}
= detail // input事件觸發(fā)時(shí),輸入框的值 // 記錄用戶行為 let query = '
'
if (isComponent) {
// 如果是組件內(nèi)的方法,需要獲取當(dāng)前組件的 tagName query = `${
this.dataset.tagName}
` }
if (id) {
// id 存在,則直接通過(guò) id 查找元素 query += id }
else {
// id 不存在,才通過(guò) className 查找元素 query += className }
addAction(type, query, value) }
return method.apply(this, args) }
}
復(fù)制代碼到這里已經(jīng)記錄了用戶所有的點(diǎn)擊、輸入、回車相關(guān)的操作。
但是還有滾動(dòng)屏幕的操作沒(méi)有記錄,我們可以直接代理 Page 的 onPageScroll 方法。
// 記錄用戶行為的數(shù)組const actions = [];
// 添加用戶行為const addAction = (type, query, value = '
'
) => {
if (type === '
scroll'
|| type === '
input'
) {
// 如果上一次行為也是滾動(dòng)或輸入,則重置 value 即可 const last = this.actions[this.actions.length - 1] if (last && last.type === type) {
last.value = value last.time = Date.now() return }
}
actions.push({
time: Date.now(), type, query, value }
) }
Page = (params) => {
const names = Object.keys(params) for (const name of names) {
// 進(jìn)行方法攔截 if (typeof obj[name] === '
function'
) {
params[name] = hookMethod(name, params[name], false) }
}
const {
onPageScroll }
= params // 攔截滾動(dòng)事件 params.onPageScroll = function (...args) {
const [evt] = args const {
scrollTop }
= evt addAction('
scroll'
, '
'
, scrollTop) onPageScroll.apply(this, args) }
originPage(params) }
復(fù)制代碼這里有個(gè)優(yōu)化點(diǎn),就是滾動(dòng)操作記錄的時(shí)候,可以判斷一下上次操作是否也為滾動(dòng)操作,如果是同一個(gè)操作,則只需要修改一下滾動(dòng)距離即可,因?yàn)閮纱螡L動(dòng)可以一步到位。
同理,輸入事件也是,輸入的值也可以一步到位。
還原用戶行為用戶操作完畢后,可以在控制臺(tái)輸出用戶行為的 json 文本,把 json 文本復(fù)制出來(lái)后,就可以通過(guò)自動(dòng)化工具運(yùn)行了。
// 引入sdkconst automator = require('
miniprogram-automator'
)// 用戶操作行為const actions = [ {
type: '
tap'
, query: '
goods .title'
, value: '
'
, time: 1596965650000 }
, {
type: '
scroll'
, query: '
'
, value: 560, time: 1596965710680 }
, {
type: '
tap'
, query: '
gotoTop'
, value: '
'
, time: 1596965770000 }
]// 啟動(dòng)微信開(kāi)發(fā)者工具automator.launch({
projectPath: '
path/to/project'
, }
).then(async miniProgram => {
let page = await miniProgram.reLaunch('
/page/index/index'
) let prevTime for (const action of actions) {
const {
type, query, value, time }
= action if (prevTime) {
// 計(jì)算兩次操作之間的等待時(shí)間 await page.waitFor(time - prevTime) }
// 重置上次操作時(shí)間 prevTime = time // 獲取當(dāng)前頁(yè)面實(shí)例 page = await miniProgram.currentPage() switch (type) {
case '
tap'
: const element = await page.$(query) await element.tap() break;
case '
input'
: const element = await page.$(query) await element.input(value) break;
case '
confirm'
: const element = await page.$(query) await element.trigger('
confirm'
, {
value }
);
break;
case '
scroll'
: await miniProgram.pageScrollTo(value) break;
}
// 每次操作結(jié)束后,等待 5s,防止頁(yè)面跳轉(zhuǎn)過(guò)程中,后面的操作找不到頁(yè)面 await page.waitFor(5000) }
// 關(guān)閉 IDE await miniProgram.close() }
)復(fù)制代碼這里只是簡(jiǎn)單的還原了用戶的操作行為,實(shí)際運(yùn)行過(guò)程中,還會(huì)涉及到網(wǎng)絡(luò)請(qǐng)求和 localstorage 的 mock,這里不再展開(kāi)講述。
同時(shí),我們還可以接入 jest 工具,更加方便用例的編寫。
總結(jié)看似很難的需求,只要用心去發(fā)掘,總能找到對(duì)應(yīng)的解決辦法。
另外微信小程序的自動(dòng)化工具真的有很多坑,遇到問(wèn)題可以先到小程序社區(qū)去找找,大部分坑都有前人踩過(guò),還有一些一時(shí)無(wú)法解決的問(wèn)題只能想其他辦法來(lái)規(guī)避。
最后祝愿天下無(wú) bug。
相關(guān)學(xué)習(xí)推薦:
微信公眾號(hào)開(kāi)發(fā)教程以上就是詳解小程序自動(dòng)化測(cè)試的詳細(xì)內(nèi)容,更多請(qǐng)關(guān)注php中文網(wǎng)其它相關(guān)文章!
微信
分享相關(guān)標(biāo)簽:
小程序 自動(dòng)化本文轉(zhuǎn)載于:
juejin,如有侵犯,請(qǐng)聯(lián)系[email protected]刪除
上一篇:
學(xué)習(xí)微信小程序如何使用echarts圖表
下一篇:
沒(méi)有了相關(guān)文章相關(guān)視頻詳解js中nightwatch的自動(dòng)化測(cè)試什么是python自動(dòng)化怎么提取微信小程序的鏈接小程序如何生成二維碼微信小程序?qū)崿F(xiàn)簽到的日歷功能詳解小程序自動(dòng)化測(cè)試小程序API接口(一)第三方平臺(tái)開(kāi)發(fā)小程序(二)(歐陽(yáng)克)微信小程序與CMS后臺(tái)認(rèn)識(shí)小程序開(kāi)發(fā)工具 [溫州做小程序]
為您推薦
- 百度智能小程序SWAN 視圖基礎(chǔ)數(shù)據(jù)綁定怎么做 2020-08-24
- 百度智能小程序SWAN 視圖是什么? 2020-08-24
- 百度智能小程序啟動(dòng)頁(yè)面的代碼如何設(shè)置 2020-08-24
- 百度智能小程序SWAN 生命周期是什么 2020-08-24
- 百度智能小程序如何配置全局?jǐn)?shù)據(jù) 2020-08-24
- 百度智能小程序?window、tabBar如何優(yōu)化和調(diào)整 2020-08-24
- 百度智能小程序?pages是什么 2020-08-24
- 百度智能小程序配置界面、路徑如何優(yōu)化 2020-08-24