前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >工具自动生成 自动化测试脚本

工具自动生成 自动化测试脚本

原创
作者头像
ronixiao
修改2022-09-20 09:56:30
1.4K0
修改2022-09-20 09:56:30
举报
文章被收录于专栏:小程序深入小程序深入

工具自动生成 自动化测试脚本-交互篇

开发工具原因

在小程序端使用自动化测试脚本,无非都是加载页面,获取节点,获取事件,获取值,获取data等操作

在断言时,也是千篇一律的拿值比较,本人觉得写一万行也是工作量的事,对自身也没有提升,也浪费时间。

但自动化在一些场合还是特别有用,修改公共组件方法,增加新的函数,尤其是与原来的逻辑存在交集的情况下,会出现漏掉检查的问题,导致模块报错出现白屏,展示不全等问题,在自动化测试交互上,可以避免一些常见容易遗忘检查的问题点。

使用方式

手动执行

进入common 执行 node start.js

根据events 里面的配置信息生成 默认auto-script(可配置修改)文件夹里面的文件engine执行逻辑拿到case类型,通过caseTmp里面的类型组装最后的文件

jest 执行对应文件名称 如 jest xxx.test.js

待完成

使用shell 执行语法一步命令解决全部终端命令

自动执行

仅仅的输入一句命令就可以执行一些复杂的人工操作

比如shell语法,在linux 系统上的脚本命令

输入 start script

执行 node start 生成脚本 -> jest xxx.text.js 执行脚本 -> 生成报告并自动打开

内部方法

获取节点名称

自动生成脚本语言,命名可以区分,单每次取名称都很繁琐

采用了

代码语言:javascript
复制
/\*\*

 \* @despripe 根据对应的 class 或 对应数据 转化为对应的驼峰命名

 \* @param {String} domName 节点

 \* @detail get name-my or .name-my.data-in or .name-my .data-in

 \* @returns input nameMy or nameMyDataIn or dataInNameMy

\*/

const handleComposeDomName = (domName) => {
  let name = ''
  const doms = domName.split(' ').reverse()
  for (let i = 0; i < doms.length; i++) {
    const rep = doms[i].replace(/[-.#\_][\_\_]{0,2}(\w)/g, (\_, c) => c ? c.toUpperCase() : '')
    name = name + rep
  }
  const first = name.substr(0,1).toLowerCase()
  return first + name.substr(1, name.length)
}
获取节点并做出操作

采用链式调用,使调取结构更加清晰

代码语言:javascript
复制
// 三个基本判断
/\* url correct example
1 初始化页面 relaunch page url 1
2 获取节点元素 page.$$
3 节点元素点击 ele[0].tap()
4 新页面路径对比 expect
\*/

/\* text corrent example
1 初始化页面 relaunch page url 1
2 获取节点元素 page.$$
3 节点元素点击 ele[0].tap()
4 新跳转页面找到目标文案 page.$$
5 新页面文案对比 expect
\*/

/\* data corrent example
1 初始化页面 relaunch page url 1
2 获取节点元素 page.$$
3 节点元素点击 ele[0].tap()
4 新跳转页面找到目标文案 page.$$
5 新页面内部data对比 expect

\*/
 /\*\*
 \* @despripe 根据对应的 class 或 对应数据 转化为对应的驼峰命名
 \* 节点操作
 \* getDom first get dom 
 \* tap second tap
 \* getMethod
 \* getText
 \* getData

\*/

const domOperate = () => {

  return {
    statement: '',
    domName: '',
    page: getPageNum(pageFactory.currentPage()),
    getDom(dom) {
      this.domName = handleComposeDomName(dom)
      this.statement = 
        `await ${this.page}.waitFor('${dom}')
        const ${this.domName} = await ${this.page}.$$('${dom}')`
      return this

    },

    tap(order) {
      const tap = `
        await ${this.domName}[${order}].tap()
        await ${this.page}.waitFor(1000)`
      this.statement = this.statement + tap
      return this.statement
    },

    getMethod() {
      return this.statement
    },
    getText(order) {
      const text = `
        const text = await ${this.domName}[${order}].text()
        await ${this.page}.waitFor(1000)`
      this.statement = this.statement + text
      return this.statement
    }
  }
}
用例类型

根据对象得格式 前两种优化版本,最后一个为未优化版本对比

代码语言:javascript
复制
const allCase = {
  // 判断路径是否正确 -> 通过点击按钮tap事件 跳转路径 对比目标路径
  urlCorrect: () => { 
    return (total) => {
      const { enterBtnDom, btnOrder, mockPage, itName, targetPath } = total
      return `
      it('${itName}', async(done) => {
        ${getRelaunchPage(mockPage)}
        ${domOperate().getDom(enterBtnDom).tap(btnOrder)}
        ${getCurrentPage(pageFactory.increasePage()).statement}
        ${expect('toBe', targetPath, getPageNum(pageFactory.currentPage()), {type: 'path'})}
        done()
      })
      `
    }
  },
  textCorrect: () => {
    return (config) => {
      const {
        enterBtnDom,
        textDom,
        targetText,
        itName,
        mockPage,
        btnOrder = 0,
        textOrder = 0,
      } = config
      /*
        函数链式调用
      */

    return `
      it('${itName}', async(done) => {
        ${getRelaunchPage(mockPage)}
        ${domOperate().getDom(enterBtnDom).tap(btnOrder)}
        ${getCurrentPage(pageFactory.increasePage()).statement}
        ${domOperate().getDom(textDom).getText(textOrder)}
        ${expect('toBe', targetText, getPageNum(pageFactory.currentPage()), {type: 'text', isSingle: true})}
        done()
      })`
    }
  },
 // 提交流程模版 未改造版本
  submit: (fn) => {
    const { mocks } = fn

    const mockData = {
      'formItems[0].value': 'test1',
      'formItems[1].value': '11111111111',
      [`formItems[${imgIndex}].value`]: mocks['img'],
      [`formItems[${imgIndex}].tempFilePaths`]: mocks['img_url'],
      [`formItems[${imgIndex}].require`]: '0',
      [`formItems[${imgIndex}].showValue`]: '1张截图',
    }
    return (fn) => {
      const { 
        firstStep,
        secondStep,
        testArea
      } = fn

      return `
        it('xxxxxx提单流程', async() => {
          const page = await miniProgram.reLaunch('/xxx/xxx/xxx')
          await page.waitFor('.xxx-xxx')
          const chooseItem = await page.$$('.xxx-xxx')
          await chooseItem[${firstStep}].tap()
          await page.waitFor(2000) // 列表页元素
          const pageTwo = await miniProgram.currentPage()
          await pageTwo.waitFor('.xxx-xxx') // 列表页元素
          const twoItem = await pageTwo.$$('.xxx-xxx')
          await twoItem[${secondStep}].tap()

          await pageTwo.waitFor(2000)
          const pageThree = await miniProgram.currentPage();
          await pageThree.waitFor('.xxx-xxx') 
          const btnItem = await pageThree.$$('.xxx-xxx')
          const chickItem = await pageThree.$$('.xxx-xxx')
          const inputItme = await pageThree.$$('.xxx-xxx-xxx-xxx')
          const textareatme = await pageThree.$$('.xxx-xxx-xxx-xxx')
        
          // pageThree.callMethod('onPrivacyCheckBoxChange')
          await inputItme[0].input('test1')
          await textareatme[0].input('xxx-xxx测试自动化-xxx')
          await chickItem[0].tap()
        
          pageThree.setData(${mockData})

          await inputItme[0].input('test2')
          await textareatme[0].input('${testArea}测试自动化-xxx')

          const data = await pageThree.data('xxx')

          // pageThree.setData({privacyChecked: true})
          await pageThree.waitFor(2000)
          await btnItem[0].tap()
          await pageThree.waitFor(2000)

          const pageFour = await miniProgram.currentPage();
          await pageFour.waitFor(4000)
      })
      `
    }
  }
}

配置文件

通过编写对象配置文件,生成对应的文件

提单流程测试格式:

代码语言:javascript
复制
 const config =  {
    isSingle: true,
    fileName: 'submitTotal',
    mocks: {},
    describes: [
      {
        describeNam: 'xxxx测试',
        cases: [
          {
            caseType: 'submit',
            caseName: 'submit',
            firstStep: 1,
            secondStep: 0,
            testArea: 'xxxx-xxxx',
            itName: 'xxxxxxxxx',
            mockPage: '/pages/xxxx/xxxxx\xxxx',
            mockData: {},
            enterBtn: '.btn',
            expect: true,
            subList: {
            }
          }
        ]
      },
    ],
    order: 1,
    targetPath: '/pages/xxxx/xxxxx',
    timeout: 300000,
    port: 9420,
  },

使用 js 对象配置

isSingle 控制 文件的 数量 单文件 存放多个 describes

fileName 文件 名称前缀 最后 存放 到 固定目录格式为 xxxx.test.js

mocks: 输入框与图片模拟信息(需加入名称电话后期增加)

describes: 数组形式, 生成对应的describe

port: 监听端口 默认 9420

目标路径判断
代码语言:javascript
复制
 const config =  {
    describeName: 'XXXX测试', // describe名称
    caseName: 'XXXX', // 文件名称
    itName: 'XXX页进入路径正确', // it 描述
    caseType: 'urlCorrect', // case类型
    mockPage: '/XXX/XXXX/XXXX', // 进入路径
    mockData: {}, // mock数据
    expect: true, // 断言
    enterBtn: '.XXXX-XXXX', // 路径进入按钮
    order: 1, // 顺序
    targetPath: '/XXXX/XXXX/XXXX', // 目标比较路径
    timeout: 300000, // jest延长响应
    port: 9420 // 监听端口
 }
目标文案判断

caseType 修改为 textCorrect 类型

对应增加

代码语言:javascript
复制
  targetText: 'XXXX', // 判断文案
  textDom: '.XXXX', // 判断文案节点
  textOrder: 0, // 第几个节点

查找节点元素

通过casetmp 生成dom查找语句,需要获取节点的 value text 值

或者后期的对比值

操作wx内置函数

待更新

storage操作

待更新

思路是这样的,至于更多,后期更新...

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 工具自动生成 自动化测试脚本-交互篇
    • 开发工具原因
      • 使用方式
        • 手动执行
        • 自动执行
        • 内部方法
        • 配置文件
        • 查找节点元素
        • 操作wx内置函数
      • 思路是这样的,至于更多,后期更新...
      相关产品与服务
      云开发 CloudBase
      云开发(Tencent CloudBase,TCB)是腾讯云提供的云原生一体化开发环境和工具平台,为200万+企业和开发者提供高可用、自动弹性扩缩的后端云服务,可用于云端一体化开发多种端应用(小程序、公众号、Web 应用等),避免了应用开发过程中繁琐的服务器搭建及运维,开发者可以专注于业务逻辑的实现,开发门槛更低,效率更高。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档