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

2022-09-20 09:56:30 浏览数 (1)

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

开发工具原因

在小程序端使用自动化测试脚本,无非都是加载页面,获取节点,获取事件,获取值,获取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/xxxxxxxxx',
            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操作

待更新

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

0 人点赞