小規模プログラムの自動テストについて詳しく解説

coldplay.xixi
リリース: 2020-08-21 17:11:47
転載
3189 人が閲覧しました

小規模プログラムの自動テストについて詳しく解説

[関連する学習の推奨事項: WeChat ミニ プログラム チュートリアル ]

背景

チームは自動化されたミニ プログラムを実行する予定ですこのツールにより、業務担当者はミニ プログラムの操作後に以前の操作パスを自動的に復元し、操作中に発生する例外をキャプチャして、このリリースがミニ プログラムの基本機能に影響を与えるかどうかを判断できるようになると期待されています。

小規模プログラムの自動テストについて詳しく解説

上記の説明は簡単なように見えますが、途中でまだ難しい点があります。最初の困難は、業務担当者が操作を行う際に、操作をどのように記録するかです。ミニプログラムのパス、2 番目の困難は、記録された操作パスを復元する方法です。

オートメーション SDK

この問題に対する操作パスを復元する方法については、公式 SDK を推奨します: miniprogram-auTomator

ミニ プログラム オートメーション SDK は、外部スクリプトを通じてミニ プログラムを制御する一連のソリューションを開発者に提供し、それによってミニ プログラムの自動テストの目的を達成します。この SDK を通じて、次のことを行うことができます。

  • ミニ プログラムを制御して指定したページにジャンプする
  • ミニ プログラム ページのデータを取得する
  • ミニ プログラムを取得するプログラム ページ要素 ステータス
  • ミニ プログラム要素バインディング イベントをトリガーします
  • コード スニペットを AppService に挿入します
  • wx オブジェクトの任意のインターフェイスを呼び出します
  • ...

上記の説明はすべて公式ドキュメントからのものです。以下の内容を読む前に公式ドキュメントを読むことをお勧めします。もちろん、これまでに puppeteer を使用したことがある場合でも、すぐに始めることができます。API は基本的に同じです。以下に、SDK の使用方法を簡単に紹介します。

// 引入sdkconst automator = require('miniprogram-automator')// 启动微信开发者工具automator.launch({  // 微信开发者工具安装路径下的 cli 工具
  // Windows下为安装路径下的 cli.bat
  // MacOS下为安装路径下的 cli
  cliPath: 'path/to/cli',  // 项目地址,即要运行的小程序的路径
  projectPath: 'path/to/project',
}).then(async miniProgram => { // miniProgram 为 IDE 启动后的实例
    // 启动小程序里的 index 页面
  const page = await miniProgram.reLaunch('/page/index/index')  // 等待 500 ms
  await page.waitFor(500)  // 获取页面元素
  const element = await page.$('.main-btn')  // 点击元素
  await element.tap()    // 关闭 IDE
  await miniProgram.close()
})复制代码
ログイン後にコピー

注意する必要があることが 1 つあります。SDK を使用する前に、開発者ツールのサービス ポートを開く必要があります。そうしないと、起動に失敗します。

小規模プログラムの自動テストについて詳しく解説
#ユーザーの行動をキャプチャする

操作パスを復元する方法を使用して、次のステップは、ユーザーの行動を記録するという問題を解決することです。操作パス。

ミニ プログラムでは、Web のようにイベント バブリングを通じてウィンドウ内のすべてのイベントをキャプチャすることはできません。幸いなことに、ミニ プログラムのすべてのページとコンポーネントは

Page を渡す必要があります。 Component メソッドをラップするため、これら 2 つのメソッドを書き換えて、受信メソッドをインターセプトし、最初のパラメーターがすべてのイベントをキャプチャする event オブジェクトであるかどうかを判断できます。

// 暂存原生方法const originPage = Pageconst originComponent = Component// 改写 PagePage = (params) => {  const names = Object.keys(params)  for (const name of names) {    // 进行方法拦截
    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) {        // 进行方法拦截
        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 // 取出第一个参数
    // 判断是否为 event 对象
    if (evt && evt.target && evt.type) {      // 记录用户行为
    }    return method.apply(this, args)
  }
}复制代码
ログイン後にコピー
ここのコードはすべてのイベント メソッドをプロキシするだけであり、ユーザーの動作を復元するために使用することはできません。ユーザーの動作を復元するには、クリック、長押し、イベント タイプなどのイベント タイプが必要かどうかも知っておく必要があります。入力。

const evtTypes = [    'tap', // 点击
    'input', // 输入
    'confirm', // 回车
    'longpress' // 长按]const hookMethod = (name, method) => {  return function(...args) {    const [evt] = args // 取出第一个参数
    // 判断是否为 event 对象
    if (
      evt && evt.target && evt.type &&
      evtTypes.includes(evt.type) // 判断事件类型
    ) {      // 记录用户行为
    }    return method.apply(this, args)
  }
}复制代码
ログイン後にコピー
イベント タイプを決定した後は、どの要素がクリックされたかを明確にする必要がありますが、ミニ プログラムの落とし穴は、イベント オブジェクトの target 属性に要素のクラス名がないことです。ただし、要素は取得できます。

小規模プログラムの自動テストについて詳しく解説
要素を正確に取得するには、構築にステップを追加し、wxml ファイルを変更し、

を変更する必要があります。すべての要素の class 属性を data-className にコピーします。

复制代码
ログイン後にコピー
しかし、クラスを取得した後、別の落とし穴があります。ミニ プログラムの自動テスト ツールは、ページ内のカスタム コンポーネントの要素を直接取得できません。最初にカスタム コンポーネントを取得する必要があります。


  {{text}}
  复制代码
ログイン後にコピー
// 如果直接查找 .toast-close 会得到 nullconst element = await page.$('.toast-close')
element.tap() // Error!// 必须先通过自定义组件的 tagName 找到自定义组件// 再从自定义组件中通过 className 查找对应元素const element = await page.$('toast .toast-close')
element.tap()复制代码
ログイン後にコピー
したがって、操作を構築するときに、要素の tagName も挿入する必要があります。

复制代码
ログイン後にコピー
これで、引き続きユーザーの行動を楽しく記録できるようになりました。

// 记录用户行为的数组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 // 取出第一个参数
    // 判断是否为 event 对象
    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事件触发时,输入框的值
      // 记录用户行为
      let query = ''
      if (isComponent) {        // 如果是组件内的方法,需要获取当前组件的 tagName
        query = `${this.dataset.tagName} `
      }      if (id) {        // id 存在,则直接通过 id 查找元素
        query += id
      } else {        // id 不存在,才通过 className 查找元素
        query += className
      }
      addAction(type, query, value)
    }    return method.apply(this, args)
  }
}复制代码
ログイン後にコピー
この時点までに、ユーザーのすべてのクリック、入力、入力関連の操作が記録されています。ただし、画面のスクロール操作は記録されないため、Page の

onPageScroll メソッドを直接プロキシすることができます。

// 记录用户行为的数组const actions = [];// 添加用户行为const addAction = (type, query, value = '') => {  if (type === 'scroll' || type === 'input') {    // 如果上一次行为也是滚动或输入,则重置 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) {    // 进行方法拦截
    if (typeof obj[name] === 'function') {
      params[name] = hookMethod(name, params[name], false)
    }
  }  const { onPageScroll } = params  // 拦截滚动事件
  params.onPageScroll = function (...args) {    const [evt] = args    const { scrollTop } = evt
    addAction('scroll', '', scrollTop)
    onPageScroll.apply(this, args)
  }
  originPage(params)
}复制代码
ログイン後にコピー
ここに最適化ポイントがあり、スクロール操作を記録したときに、最後の操作もスクロール操作であったかどうかを判断できます。同じ操作であれば、変更するだけで済みます。スクロール距離は 2 つなので、2 番目のスクロールは 1 つのステップで実行できます。入力イベントについても同様で、入力値まで1ステップで到達できます。

ユーザー動作の復元

ユーザー操作が完了すると、ユーザー動作の JSON テキストがコンソールに出力されます。JSON テキストをコピーした後、自動化ツールを通じて実行できます。 。

// 引入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 }
]// 启动微信开发者工具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) {      // 计算两次操作之间的等待时间
        await page.waitFor(time - prevTime)
    }    // 重置上次操作时间
    prevTime = time    
    // 获取当前页面实例
    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;
    }    // 每次操作结束后,等待 5s,防止页面跳转过程中,后面的操作找不到页面
    await page.waitFor(5000)
  }    // 关闭 IDE
  await miniProgram.close()
})复制代码
ログイン後にコピー
これはユーザーの操作動作を単純に復元しただけであり、実際の操作ではネットワーク リクエストやローカルストレージのモックも関係しますが、ここでは説明しません。同時に、jest ツールにアクセスして、ユースケースを簡単に作成することもできます。

まとめ

一見難しいニーズでも、慎重に調査する限り、対応するソリューションを常に見つけることができます。さらに、WeChat ミニ プログラムの自動化ツールには本当に多くの落とし穴があります。問題が発生した場合は、まずミニ プログラム コミュニティにアクセスして問題を見つけることができます。ほとんどの落とし穴は前任者によって踏まれています。また、いくつかの落とし穴もあります。現時点では解決できず、他の方法で解決するしかない問題は避けてください。最後に、世界からバグがなくなることを願っています。

関連する学習に関する推奨事項: WeChat パブリック アカウント開発チュートリアル

以上が小規模プログラムの自動テストについて詳しく解説の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:juejin.im
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート
私たちについて 免責事項 Sitemap
PHP中国語ウェブサイト:福祉オンライン PHP トレーニング,PHP 学習者の迅速な成長を支援します!