一、缘起-为什么要进行小程序自动化测试
微信小程序生态日益完善,很多小程序项目页面越来越多,结构越来越复杂,业务逻辑也更加多样。以腾讯课堂小程序为例,目前腾讯课堂小程序部分页面结构和不同业务场景下的表现如下图所示:
可以看到在核心功能上主要页面对于不同业务场景有众多不同的表现,因此在开发与发布的过程中需要手动验证大量测试用例以保证小程序按预期表现运行,善于利用工具的程序员当然会想:
这种重复的工作能不能交给程序自动进行呢?
web开发中对于这类测试问题已经有了很多自动化解决方案比如Selenium、Puppeteer,思路大体相同,都是让浏览器按照指定顺序自动在页面上完成点击、输入等操作,再将操作后的页面表现与想要得到的结果进行比较得到测试结论(断言)。那小程序中有没有一种方案能够按照这种思路实现自动化操作并提供页面信息用于断言呢?为了微信底层安全考虑,小程序环境一直比较封闭,留给开发者操作的余地很小,自动化操作基本无法实现,但5月底出现了miniprogram-automator工具,给了小程序开发者希望。
二、缘遇-初试miniprogram-automator
基于miniprogram-automator的文档描述简单总结一下,当通过命令打开开发版微信开发者工具的自动化接口并连接自动化接口后,此工具可提供以下能力:
- MiniProgram:获取小程序信息(页面堆栈、系统信息、页面内容),控制小程序(跳转页面、切换tab、调用方法)
- Page:获取页面信息(路径、元素、数据、结构),控制页面(设置渲染数据、调用方法)
- Element:获取元素信息(属性、样式、内容、位置),操控元素(点击、长按、调用方法)
所以小程序自动化控制的实现依赖于开发版小程序开发者工具以及miniprogram-automator工具。小程序开发者工具命令行用来打开指定自动化操作服务端口。(开发者工具版本需高于v1.02.1906042)。miniprogram-automator工具用来操作开发者工具中运行的小程序并获取所需的信息。对于测试需求可以结合jest框架进行测试用例的组织和断言。
不多废话,看完文档用一下:
Ø 调用开发者工具命令行打开项目与指定自动化操作服务端口
复制代码
PS D:\programs\内测\微信web开发者工具> ./cli.bat --auto D:\weApp\testMiniprogram --auto-port 9420 Initializing... idePortFile: C:\Users\billcui\AppData\Local\微信开发者工具\User Data\Default\.ide starting ide... IDE server has started, listening on http://127.0.0.1:35510 initialization finished Open project with automation enabled success D:\weApp\testMiniprogram
这一行命令需要注意的有:
- 文档要求开发者工具版本号必须高于v1.02.1906042,最好是最新的内测版工具,我是在v1.03.1906062运行成功的;
- 运行这行命令之前需要先打开开发者工具菜单中的设置->安全设置->服务端口;
- 自动化端口是独立于服务端口的(比如终端打印出的35510其实是服务端口),必须要看到
Open project with automation enabled success D:\weApp\testMiniprogram
这行提示才算是成功打开了自动化端口(9420)。
命令运行成功后,开发者工具会自动打开项目,并弹出提示
Ø npm i miniprogram-automator --save-dev
安装SDK,创建test.js,代码中引入miniprogram-automator工具,连接自动化操作端口
复制代码
const automator = require('miniprogram-automator'); const miniProgram = automator.connect({ wsEndpoint: 'ws://localhost:9420', })
Ø 利用miniprogram-automator提供的接口操作小程序从首页重启并进行相关操作
复制代码
const automator = require('miniprogram-automator'); const miniProgram = automator.connect({ wsEndpoint: 'ws://localhost:9420', }).then(async miniProgram => { // 从首页重启 const page = await miniProgram.reLaunch('/pages/index/index'); // 从页面获取bottom-button组件 const button = await page.$('botto