欧美三级国产三级日韩三级_亚洲熟妇丰满大屁股熟妇_欧美亚洲成人一区二区三区_国产精品久久久久久模特

小程序自動(dòng)化測(cè)試 - 新聞資訊 - 云南小程序開(kāi)發(fā)|云南軟件開(kāi)發(fā)|云南網(wǎng)站建設(shè)-昆明葵宇信息科技有限公司

159-8711-8523

云南網(wǎng)建設(shè)/小程序開(kāi)發(fā)/軟件開(kāi)發(fā)

知識(shí)

不管是網(wǎng)站,軟件還是小程序,都要直接或間接能為您產(chǎn)生價(jià)值,我們?cè)谧非笃湟曈X(jué)表現(xiàn)的同時(shí),更側(cè)重于功能的便捷,營(yíng)銷的便利,運(yùn)營(yíng)的高效,讓網(wǎng)站成為營(yíng)銷工具,讓軟件能切實(shí)提升企業(yè)內(nèi)部管理水平和效率。優(yōu)秀的程序?yàn)楹笃谏?jí)提供便捷的支持!

您當(dāng)前位置>首頁(yè) » 新聞資訊 » 小程序相關(guān) >

小程序自動(dòng)化測(cè)試

發(fā)表時(shí)間:2020-10-26

發(fā)布人:葵宇科技

瀏覽次數(shù):53

背景

近期團(tuán)隊(duì)打算做一個(gè)小程序自動(dòng)化測(cè)試的工具,期望能夠做的業(yè)務(wù)人員操作一遍小程序后,自動(dòng)還原之前的操作路徑,并且捕獲操作過(guò)程中發(fā)生的異常,以此來(lái)判斷這次發(fā)布時(shí)候會(huì)影響小程序的基礎(chǔ)功能。

在這里插入圖片描述
上述描述看似簡(jiǎn)單,但是中間還是有些難點(diǎn)的,第一個(gè)難點(diǎn)就是如何在業(yè)務(wù)人員操作小程序的時(shí)候記錄操作路徑,第二個(gè)難點(diǎn)就是如何將記錄的操作路徑進(jìn)行還原。

自動(dòng)化 SDK

如何將操作路徑還原這個(gè)問(wèn)題,當(dāng)然首選官方提供的 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 ,基本是無(wú)縫銜接。下面簡(jiǎn)單介紹下 SDK 的使用方式。

如果對(duì)軟件測(cè)試、接口、自動(dòng)化、性能測(cè)試、測(cè)試開(kāi)發(fā)、面試經(jīng)驗(yàn)交流。感興趣可以1079636098,群內(nèi)會(huì)有不定期的發(fā)放免費(fèi)的資料鏈接,這些資料都是從各個(gè)技術(shù)網(wǎng)站搜集、整理出來(lái)的,如果你有好的學(xué)習(xí)資料可以私聊發(fā)我,我會(huì)注明出處之后分享給大家。

// 引入sdk
const 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()
})

有個(gè)地方需要提醒一下:使用 SDK 之前需要開(kāi)啟開(kāi)發(fā)者工具的服務(wù)端口,要不然會(huì)啟動(dòng)失敗。
在這里插入圖片描述

捕獲用戶行為

有了還原操作路徑的辦法,接下來(lái)就要解決記錄操作路徑的難題了。

在小程序中,并不能像 web 中通過(guò)事件冒泡的方式在 window 中捕獲所有的事件,好在小程序所以的頁(yè)面和組件都必須通過(guò) Page 、 Component 方法來(lái)包裝,所以我們可以改寫(xiě)這兩個(gè)方法,攔截傳入的方法,并判斷第一個(gè)參數(shù)是否為 event 對(duì)象,以此來(lái)捕獲所有的事件。

// 暫存原生方法
const originPage = Page
const originComponent = Component

// 改寫(xiě) Page
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)
    }
  }
  originPage(params)
}
// 改寫(xiě) Component
Component = (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)
  }
}

這里的代碼只是代理了所有的事件方法,并不能用來(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)
  }
}

確定事件類型之后,還需要明確點(diǎn)擊的元素到底是哪個(gè),但是小程序里面比較坑的地方就是,event 對(duì)象的 target 屬性中,并沒(méi)有元素的類名,但是可以獲取元素的 dataset。
在這里插入圖片描述
為了準(zhǔn)確的獲取元素,我們需要在構(gòu)建中增加一個(gè)步驟,修改 wxml 文件,將所以元素的 class 屬性復(fù)制一份到 data-className 。

<!-- 構(gòu)建前 -->
<view class="close-btn"></view>
<view class="{{mainClassName}}"></view>
<!-- 構(gòu)建后 -->
<view class="close-btn" data-className="close-btn"></view>
<view class="{{mainClassName}}" data-className="{{mainClassName}}"></view>

但是獲取到 class 之后,又會(huì)有另一個(gè)坑,小程序的自動(dòng)化測(cè)試工具并不能直接獲取頁(yè)面里自定義組件中的元素,必須先獲取自定義組件。

<!-- Page -->
<toast text="loading" show="{{showToast}}" />
<!-- Component -->
<view class="toast" wx:if="{{show}}">
  <text class="toast-text">{{text}}</text>
  <view class="toast-close" />
</view>
// 如果直接查找 .toast-close 會(huì)得到 null
const element = await page.$('.toast-close')
element.tap() // Error!

// 必須先通過(guò)自定義組件的 tagName 找到自定義組件
// 再?gòu)淖远x組件中通過(guò) className 查找對(duì)應(yīng)元素
const element = await page.$('toast .toast-close')
element.tap()

所以我們?cè)跇?gòu)建操作的時(shí)候,還需要為元素插入 tagName。

<!-- 構(gòu)建前 -->
<view class="close-btn" />
<toast text="loading" show="{{showToast}}" />
<!-- 構(gòu)建后 -->
<view class="close-btn" data-className="close-btn" data-tagName="view" />
<toast text="loading" show="{{showToast}}" data-tagName="toast" />

現(xiàn)在我們可以繼續(xù)愉快的記錄用戶行為了。

// 記錄用戶行為的數(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)
  }
}

到這里已經(jīng)記錄了用戶所有的點(diǎn)擊、輸入、回車相關(guān)的操作,但是還有一個(gè)滾動(dòng)屏幕的操作還沒(méi)記錄。這里可以直接監(jiān)聽(tīng) Page 的 rel="stylesheet">

相關(guān)案例查看更多