小程序自动化测试的示例分析

小编给大家分享一下小程序自动化测试的示例分析,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!

背景

近期团队打算做一个小程序自动化测试的工具,期望能够做到业务人员操作一遍小程序后,自动还原之前的操作路径,并且捕获操作过程中发生的异常,以此来判断这次发布是否会影响小程序的基础功能。

小程序自动化测试的示例分析

上述描述看似简单,但是中间还是有些难点的,第一个难点就是如何在业务人员操作小程序的时候记录操作路径,第二个难点就是如何将记录的操作路径进行还原。

自动化 SDK

如何将操作路径还原这个问题,首选官方提供的 SDK: miniprogram-automator

小程序自动化 SDK 为开发者提供了一套通过外部脚本操控小程序的方案,从而实现小程序自动化测试的目的。通过该 SDK,你可以做到以下事情:

  • 控制小程序跳转到指定页面

  • 获取小程序页面数据

  • 获取小程序页面元素状态

  • 触发小程序元素绑定事件

  • 往 AppService 注入代码片段

  • 调用 wx 对象上任意接口

  • ...

上面的描述都来自官方文档,建议阅读后面内容之前可以先看看官方文档,当然如果之前用过 puppeteer ,也可以快速上手,api 基本一致。下面简单介绍下 SDK 的使用方式。

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

有个地方需要提醒一下:使用 SDK 之前需要开启开发者工具的服务端口,要不然会启动失败。

小程序自动化测试的示例分析

捕获用户行为

有了还原操作路径的办法,接下来就要解决记录操作路径的难题了。

在小程序中,并不能像 web 中通过事件冒泡的方式在 window 中捕获所有的事件,好在小程序所以的页面和组件都必须通过 PageComponent 方法来包装,所以我们可以改写这两个方法,拦截传入的方法,并判断第一个参数是否为 event 对象,以此来捕获所有的事件。

//暂存原生方法constoriginPage=PageconstoriginComponent=Component//改写PagePage=(params)=>{constnames=Object.keys(params)for(constnameofnames){//进行方法拦截
if(typeofobj[name]==='function'){
params[name]=hookMethod(name,params[name],false)
}
}
originPage(params)
}//改写ComponentComponent=(params)=>{if(params.methods){const{methods}=paramsconstnames=Object.keys(methods)for(constnameofnames){//进行方法拦截
if(typeofmethods[name]==='function'){
methods[name]=hookMethod(name,methods[name],true)
}
}
}
originComponent(params)
}consthookMethod=(name,method,isComponent)=>{returnfunction(...args){const[evt]=args//取出第一个参数
//判断是否为event对象
if(evt&&evt.target&&evt.type){//记录用户行为
}returnmethod.apply(this,args)
}
}复制代码

这里的代码只是代理了所有的事件方法,并不能用来还原用户的行为,要还原用户行为还必须知道该事件类型是否是需要的,比如点击、长按、输入。

constevtTypes=['tap',//点击
'input',//输入
'confirm',//回车
'longpress'//长按]consthookMethod=(name,method)=>{returnfunction(...args){const[evt]=args//取出第一个参数
//判断是否为event对象
if(
evt&&evt.target&&evt.type&&
evtTypes.includes(evt.type)//判断事件类型
){//记录用户行为
}returnmethod.apply(this,args)
}
}复制代码

确定事件类型之后,还需要明确点击的元素到底是哪个,但是小程序里面比较坑的地方就是,event 对象的 target 属性中,并没有元素的类名,但是可以获取元素的 dataset。

小程序自动化测试的示例分析

为了准确的获取元素,我们需要在构建中增加一个步骤,修改 wxml 文件,将所有元素的 class 属性复制一份到 data-className 中。

<!--构建前--><viewclass="close-btn"></view><viewclass="{{mainClassName}}"></view><!--构建后--><viewclass="close-btn"data-className="close-btn"></view><viewclass="{{mainClassName}}"data-className="{{mainClassName}}"></view>复制代码

但是获取到 class 之后,又会有另一个坑,小程序的自动化测试工具并不能直接获取页面里自定义组件中的元素,必须先获取自定义组件。

<!--Page--><toasttext="loading"show="{{showToast}}"/><!--Component--><viewclass="toast"wx:if="{{show}}">
<textclass="toast-text">{{text}}</text>
<viewclass="toast-close"/></view>复制代码
//如果直接查找.toast-close会得到nullconstelement=awaitpage.$('.toast-close')
element.tap()//Error!//必须先通过自定义组件的tagName找到自定义组件//再从自定义组件中通过className查找对应元素constelement=awaitpage.$('toast.toast-close')
element.tap()复制代码

所以我们在构建操作的时候,还需要为元素插入 tagName。

<!--构建前--><viewclass="close-btn"/><toasttext="loading"show="{{showToast}}"/><!--构建后--><viewclass="close-btn"data-className="close-btn"data-tagName="view"/><toasttext="loading"show="{{showToast}}"data-tagName="toast"/>复制代码

现在我们可以继续愉快的记录用户行为了。

//记录用户行为的数组constactions=[];//添加用户行为constaddAction=(type,query,value='')=>{
actions.push({time:Date.now(),
type,
query,
value
})
}//代理事件方法consthookMethod=(name,method,isComponent)=>{returnfunction(...args){const[evt]=args//取出第一个参数
//判断是否为event对象
if(
evt&&evt.target&&evt.type&&
evtTypes.includes(evt.type)//判断事件类型
){const{type,target,detail}=evtconst{id,dataset={}}=targetconst{className=''}=datasetconst{value=''}=detail//input事件触发时,输入框的值
//记录用户行为
letquery=''
if(isComponent){//如果是组件内的方法,需要获取当前组件的tagName
query=`${this.dataset.tagName}`
}if(id){//id存在,则直接通过id查找元素
query+=id
}else{//id不存在,才通过className查找元素
query+=className
}
addAction(type,query,value)
}returnmethod.apply(this,args)
}
}复制代码

到这里已经记录了用户所有的点击、输入、回车相关的操作。但是还有滚动屏幕的操作没有记录,我们可以直接代理 Page 的 onPageScroll 方法。

//记录用户行为的数组constactions=[];//添加用户行为constaddAction=(type,query,value='')=>{if(type==='scroll'||type==='input'){//如果上一次行为也是滚动或输入,则重置value即可
constlast=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)=>{constnames=Object.keys(params)for(constnameofnames){//进行方法拦截
if(typeofobj[name]==='function'){
params[name]=hookMethod(name,params[name],false)
}
}const{onPageScroll}=params//拦截滚动事件
params.onPageScroll=function(...args){const[evt]=argsconst{scrollTop}=evt
addAction('scroll','',scrollTop)
onPageScroll.apply(this,args)
}
originPage(params)
}复制代码

这里有个优化点,就是滚动操作记录的时候,可以判断一下上次操作是否也为滚动操作,如果是同一个操作,则只需要修改一下滚动距离即可,因为两次滚动可以一步到位。同理,输入事件也是,输入的值也可以一步到位。

还原用户行为

用户操作完毕后,可以在控制台输出用户行为的 json 文本,把 json 文本复制出来后,就可以通过自动化工具运行了。

//引入sdkconstautomator=require('miniprogram-automator')//用户操作行为constactions=[
{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(asyncminiProgram=>{letpage=awaitminiProgram.reLaunch('/page/index/index')
letprevTimefor(constactionofactions){const{type,query,value,time}=actionif(prevTime){//计算两次操作之间的等待时间
awaitpage.waitFor(time-prevTime)
}//重置上次操作时间
prevTime=time
//获取当前页面实例
page=awaitminiProgram.currentPage()switch(type){case'tap':constelement=awaitpage.$(query)awaitelement.tap()break;case'input':constelement=awaitpage.$(query)awaitelement.input(value)break;case'confirm':constelement=awaitpage.$(query)awaitelement.trigger('confirm',{value});break;case'scroll':awaitminiProgram.pageScrollTo(value)break;
}//每次操作结束后,等待5s,防止页面跳转过程中,后面的操作找不到页面
awaitpage.waitFor(5000)
}//关闭IDE
awaitminiProgram.close()
})复制代码

这里只是简单的还原了用户的操作行为,实际运行过程中,还会涉及到网络请求和 localstorage 的 mock,这里不再展开讲述。同时,我们还可以接入 jest 工具,更加方便用例的编写。

看完了这篇文章,相信你对“小程序自动化测试的示例分析”有了一定的了解,如果想了解更多相关知识,欢迎关注恰卡编程网行业资讯频道,感谢各位的阅读!

发布于 2021-03-13 15:40:54
收藏
分享
海报
0 条评论
165
上一篇:微信被限制登录的原因有哪些 下一篇:Laravel 7新功能有哪些
目录

    0 条评论

    本站已关闭游客评论,请登录或者注册后再评论吧~

    忘记密码?

    图形验证码