Heim  >  Artikel  >  WeChat-Applet  >  Detaillierte Erläuterung des automatisierten Testens kleiner Programme

Detaillierte Erläuterung des automatisierten Testens kleiner Programme

coldplay.xixi
coldplay.xixinach vorne
2020-08-21 17:11:193333Durchsuche

🔜 den Miniprogrammpfad und erfassen Sie Ausnahmen, die während des Vorgangs auftreten, um festzustellen, ob diese Version Auswirkungen auf die Grundfunktionen des Miniprogramms hat.

Detaillierte Erläuterung des automatisierten Testens kleiner Programme

Die obige Beschreibung scheint einfach zu sein, aber es gibt immer noch einige Schwierigkeiten in der Mitte. Die erste Schwierigkeit besteht darin, den Betriebspfad aufzuzeichnen, wenn das Geschäftspersonal das Miniprogramm bedient, und die zweite Schwierigkeit besteht darin, wie man es durchführt den aufgezeichneten Operationspfad aus.

Automatisierungs-SDK

Wie stellt man den Betriebspfad wieder her? Für dieses Problem wird das offizielle SDK bevorzugt:
. Detaillierte Erläuterung des automatisierten Testens kleiner Programme
Das Mini Program Automation SDK bietet Entwicklern eine Reihe von Lösungen zur Steuerung von Miniprogrammen über externe Skripte und erreicht so den Zweck des automatisierten Testens von Miniprogrammen. Mit diesem SDK können Sie Folgendes tun:

Steuern Sie das Miniprogramm, um zur angegebenen Seite zu springen

Abrufen der Miniprogramm-Seitendaten

Abrufen des Miniprogramm-Seitenelementstatus miniprogram-automator

Auslösen des Miniprogramm-Elementbindungsereignisses

Gehen Sie zu AppService Inject Code Snippets.
  • Rufen Sie eine beliebige Schnittstelle für das WX-Objekt auf Wenn Sie Puppeteer bereits verwendet haben, können Sie auch schnell loslegen. Die API ist im Grunde dieselbe. Im Folgenden finden Sie eine kurze Einführung in die Verwendung des 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()
})复制代码
  • Eines muss beachtet werden: Bevor Sie das SDK verwenden, müssen Sie den Service-Port der Entwicklertools öffnen, sonst schlägt der Start fehl.
  • Erfassen des Benutzerverhaltens
  • Mit der Methode zur Wiederherstellung des Betriebspfads besteht der nächste Schritt darin, das Problem der Aufzeichnung des Betriebspfads zu lösen.
  • Im Miniprogramm ist es nicht möglich, alle Ereignisse im Fenster wie im Web durch Event-Bubbling zu erfassen. Glücklicherweise müssen alle Seiten und Komponenten des Miniprogramms über die Methoden und

    gepackt werden, damit wir sie neu schreiben können Diese beiden Methoden fangen die eingehende Methode ab und bestimmen, ob der erste Parameter ein

    -Objekt ist, um alle Ereignisse zu erfassen.

    // 暂存原生方法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)
      }
    }复制代码
    Der Code hier stellt nur alle Ereignismethoden dar und kann nicht zum Wiederherstellen des Benutzerverhaltens verwendet werden. Um das Verhalten des Benutzers wiederherzustellen, müssen Sie auch wissen, ob der Ereignistyp erforderlich ist, z. B. Klicken, langes Drücken und Eingabe.
    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)
      }
    }复制代码
    Detaillierte Erläuterung des automatisierten Testens kleiner ProgrammeNachdem Sie den Ereignistyp ermittelt haben, müssen Sie noch klären, auf welches Element geklickt wurde. Die Gefahr des Miniprogramms besteht jedoch darin, dass das Zielattribut des Ereignisobjekts nicht den Klassennamen des Elements, sondern den Datensatz davon enthält Das Element kann erhalten werden.

    Um die Elemente genau zu erhalten, müssen wir einen Schritt in der Konstruktion hinzufügen, die WXML-Datei ändern und die

    -Attribute aller Elemente nach Page kopieren. Component

    <!-- 构建前 --><view></view><view></view><!-- 构建后 --><view></view><view></view>复制代码
    eventAber nach dem Erhalt der Klasse gibt es eine weitere Gefahr. Das automatisierte Testtool des Miniprogramms kann die Elemente in der benutzerdefinierten Komponente auf der Seite nicht direkt abrufen.
    <!-- Page --><toast></toast><!-- Component --><view>
      <text>{{text}}</text>
      <view></view></view>复制代码
    // 如果直接查找 .toast-close 会得到 nullconst element = await page.$('.toast-close')
    element.tap() // Error!// 必须先通过自定义组件的 tagName 找到自定义组件// 再从自定义组件中通过 className 查找对应元素const element = await page.$('toast .toast-close')
    element.tap()复制代码

    Wenn wir also die Operation erstellen, müssen wir auch tagName für das Element einfügen.

    <!-- 构建前 --><view></view><toast></toast><!-- 构建后 --><view></view><toast></toast>复制代码

    Jetzt können wir weiterhin fröhlich das Nutzerverhalten aufzeichnen.

    // 记录用户行为的数组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)
      }
    }复制代码
    Bisher wurden alle Klicks, Eingaben und Eingabevorgänge des Benutzers aufgezeichnet. Es gibt jedoch immer noch einen Vorgang zum Scrollen des Bildschirms, der nicht aufgezeichnet wird. Wir können die Detaillierte Erläuterung des automatisierten Testens kleiner Programme-Methode von Page direkt delegieren.
    // 记录用户行为的数组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)
    }复制代码
    Hier gibt es einen Optimierungspunkt. Wenn der Bildlaufvorgang aufgezeichnet wird, können Sie beurteilen, ob der letzte Vorgang auch ein Bildlaufvorgang war. Wenn es sich um denselben Vorgang handelt, müssen Sie nur den Bildlaufabstand ändern An Ort und Stelle können zwei Schriftrollen in einem Schritt ausgeführt werden. Das Gleiche gilt auch für Eingabeereignisse, und der Eingabewert kann auch in einem Schritt erreicht werden.

    Benutzerverhalten wiederherstellenclassdata-classNameNachdem der Benutzervorgang abgeschlossen ist, kann der JSON-Text des Benutzerverhaltens in der Konsole ausgegeben werden. Nach dem Kopieren des JSON-Textes kann dieser über das Automatisierungstool ausgeführt werden.

    // 引入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()
    })复制代码

    Dies ist nur eine einfache Wiederherstellung des Betriebsverhaltens des Benutzers. Während des eigentlichen Betriebs sind auch Netzwerkanforderungen und lokale Speichermocks beteiligt, die hier nicht beschrieben werden. Gleichzeitig können wir auch auf das Jest-Tool zugreifen, um das Schreiben von Anwendungsfällen zu erleichtern.

    Zusammenfassung

    Für scheinbar schwierige Bedürfnisse können Sie immer die entsprechende Lösung finden, solange Sie sie sorgfältig untersuchen. Darüber hinaus gibt es in den Automatisierungstools von WeChat-Miniprogrammen wirklich viele Fallstricke. Wenn Sie auf Probleme stoßen, können Sie diese zunächst in der Miniprogramm-Community finden Probleme, die im Moment nicht gelöst werden können und die man nur auf andere Weise lösen kann. Abschließend wünsche ich mir, dass die Welt fehlerfrei ist.

    Verwandte Lernempfehlungen: Tutorial zur Entwicklung eines öffentlichen WeChat-Kontos

    Das obige ist der detaillierte Inhalt vonDetaillierte Erläuterung des automatisierten Testens kleiner Programme. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

  • Stellungnahme:
    Dieser Artikel ist reproduziert unter:juejin.im. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen