大家好,我是小码哥,今天整理了一份minium微信小程序自动化测试框架手册,希望能对你有帮助!
目录
简介
特性
暂不支持
快速开始
运行环境
必要的知识
安装
开始使用
更多能力
常见问题排查
测试进阶
framework
一个简单例子
目录结构
编写第一个case
编写配置文件
运行case
查看结果
Class minium.MiniTest
命令行工具
minitest 命令
测试计划
目录结构
编写测试计划
运行测试计划
测试结果
测试报告
真机测试
Android
IOS
安装 libmobiledevice
配置 WebDriverAgent
配置测试 config.json
项目配置
Android的device_desire配置项
IOS的device_desire配置项
IDE的mock_native_modal配置项
mock_request配置项
例子
元素定位
简单选择器
多账号
minium 是为小程序专门开发的自动化框架, 提供了 Python 版本。使用 minium 可以进行小程序 UI 自动化测试, 但是 minium 的功能不止于仅仅是 UI 自动化, 甚至可以使用 minium 来进行函数的 mock, 可以直接跳转到小程序某个页面并设置页面数据, 做针对性的全面测试, 这些都得益于我们开放了部分小程序 API 的能力。除此之外,小程序有部分组件使用了系统原生的组件,对于这部分的组件,我们也基于 uiautomator 和 wda 做了补充。
目前小程序的体量越来越大,相关的框架和组件库越来越多,对于测试能力要求也越来越高。业内同行基于Chrome DevTools Protocol开发了很多小程序相关的测试工具,这些工具都有以下缺点:
而 minium
除了以上缺点都没有之外,还支持以下更多特性:
设置 -> 安全设置 -> 服务端口: 打开
本框架与开发者工具有强关联,如果你之前对开发者工具没有基本的了解,可以点击下面的链接了解一些必要的知识:
下载minium安装包,然后执行:
pip3 install minium-latest.zip
Copy to clipboardErrorCopied
亦或者下载解压之后执行:
python3 setup.py install
Copy to clipboardErrorCopied
安装完成后,可执行以下命令查看版本:
minitest -v
Copy to clipboardErrorCopied
以下是参考代码,输出system_info
import minium
mini = minium.Minium({
"project_path": "path/to/project", # 小程序项目目录地址
"dev_tool_path": "path/to/cli" # 开发者工具cli地址,如果没有修改过默认安装路径可不填此项
})
print(mini.get_system_info())
Copy to clipboardErrorCopied
以上是minium接口的基本用法,minium还集成了测试框架,给你提供更多的测试能力。详情见测试进阶
MiniConfigError: dev_tool_path: /Applications/wechatwebdevtools.app/Contents/MacOS/cli not exists
解决方法:
dev_tool_path
路径或实例化的时候加上dev_tool_path
选项。参考测试配置或例子检查方法:
"path/to/cli" auto --project "path/to/project" --auto-port 9420
Copy to clipboardErrorCopied
MiniLaunchError: Open project in automation mode fail! Please ensure you have permission of project and have not environ error
解决方法:
receive from remote timeout, id: 99eb239c-a2a3-4a12-80da-6fd0312e768f
解决方法:
使用MiniTest可以大大降低小程序测试成本。如何快速使用测试框架进行测试,可参考例子
minium提供一个基于unittest封装好的测试框架,利用这个简单的框架对小程序测试可以起到事半功倍的效果。
测试基类Minitest会根据测试配置进行测试,minitest向上继承了unittest.TestCase
,并做了以下改动:
.
├── test
│ └── __init__.py
│ └── first_test.py
└── config.json
Copy to clipboardErrorCopied
编辑case文件first_test.py
#!/usr/bin/env python3
import minium
class FirstTest(minium.MiniTest):
def test_get_system_info(self):
sys_info = self.mini.get_system_info()
self.assertIn("SDKVersion", sys_info)
Copy to clipboardErrorCopied
编辑配置文件config.json
{
"project_path": "/Users/yopofeng/workspace/miniprograms/devtools-test/demo",
"debug_mode": "info"
}
Copy to clipboardErrorCopied
更多配置信息请参考测试配置
minitest -m test.first_test -c config.json -g
Copy to clipboardErrorCopied
test.first_test
是python包名,不要跟path搞混
更多命令行参数请参考命令行工具
运行结果如下:
测试结果存储在outputs
下,运行命令python3 -m http.server 12345 -d outputs
然后在浏览器上访问http://localhost:12345
即可查看报告,如图:
MiniTest
是minium中继承自unittest.TestCase
的测试基类
Properties:
名称 | 类型 | 默认值 | 说明 |
---|---|---|---|
mini | minium.Minium | None | Minium实例,可直接调用minium.Minium中的方法 |
app | minium.App | None | App实例,可直接调用minium.App中的方法 |
native | minium.Native | None | Native实例,可直接调用minium.Native中的方法 |
代码示例:
#!/usr/bin/env python3
import minium
class FirstTest(minium.MiniTest):
def test_get_system_info(self):
sys_info = self.mini.get_system_info()
self.assertIn("SDKVersion", sys_info)
Copy to clipboardErrorCopied
运行
参考例子
测试用例的执行可以用执行unittest的方式,也可以用我们提供的脚本minitest
来加载用例,相关的参数说明如下:
-h, --help: 使用帮助。
-v, --version: 查看 minium 的版本。
-p PATH/--path PATH: 用例所在的文件夹,默认当前路径。
-m MODULE_PATH, --module MODULE_PATH: 用例的包名或者文件名
--case CASE_NAME: test_
开头的用例名
-s SUITE, --suite SUITE:测试计划文件,文件的格式如下:
{
"pkg_list": [
{
"case_list": [
"test_*"
],
"pkg": "test.*_test"
}
]
}
Copy to clipboardErrorCopied
suite.json的pkg_list
字段说明要执行用例的内容和顺序,pkg_list
是一个数组,每个数组元素是一个匹配规则,会根据pkg
去匹配包名,找到测试类,然后再根据case_list
里面的规则去查找测试类的测试用例。可以根据需要编写匹配的粒度。注意匹配规则不是正则表达式,而是通配符。
测试文件可以指定特定的用例,规定执行顺序
-c CONFIG, --config CONFIG:配置文件名,配置项目参考配置文件
-g, --generate: 生成网页测试报告
--module_search_path [SYS_PATH_LIST [SYS_PATH_LIST ...]]: 添加 module 的搜索路径
-a, --accounts: 查看开发者工具当前登录的多账号, 需要通过 9420 端口,以自动化模式打开开发者工具
--mode RUN_MODE: 选择以parallel
(并行)或者fork
(复刻)的方式运行用例
测试项目中一般包含大量的测试case,在不同的测试阶段可能需要选取不同的case运行,因此项目中需要配置不同的测试计划
以下是一个使用测试计划进行配置的例子
.
├── test
│ └── __init__.py
│ └── first_test.py
│ └── second_test.py
└── config.json
└── suite.json
Copy to clipboardErrorCopied
case
和配置
编写可参考例子
编辑suite文件suite.json
{
"pkg_list": [
{
"case_list": [
"test_*"
],
"pkg": "test.*_test"
}
]
}
Copy to clipboardErrorCopied
suite.json的pkg_list
字段说明要执行用例的内容和顺序,pkg_list
是一个数组,每个数组元素是一个匹配规则,会根据pkg
去匹配包名,找到测试类,然后再根据case_list
里面的规则去查找测试类的测试用例。可以根据需要编写匹配的粒度。注意匹配规则不是正则表达式,而是通配符。
minitest -s suite.json -c config.json -g
Copy to clipboardErrorCopied
更多命令行参数请参考命令行工具
每条用例的测试结果我们会存放到一个目录里面,里面包含:
基于这些数据可以生成测试报告,也可以做一些存档的事情。
根据用例的执行结果,我们基于Vue和element提供一个简洁的测试报告:例子。
报告生成有2种方式:
-g
参数minireport input_path output_path
Copy to clipboardErrorCopied
output_path
里面会生成有报告的入口。生成报告之后,在对应的目录下面有index.html文件,但是我们不能直接用浏览器打开这个 文件,需要把这个目录放到一个静态服务器上。以下方式都是可行的:
本地执行python3 -m http.server 12345 -d /path/to/dir/of/report
,然后浏览器输入:http://localhost:12345/
PS: 其中/path/to/dir/of/report
为上文的output_path
利用nginx的配置:
server {
listen 80;
server_name your.domain.com;
location / {
alias /path/to/dir/of/report;
index index.html;
}
}
minium通过配置文件来识别小程序运行的平台,如果需要测试手机上的小程序,那么需要把配置项platform
改成Android
或者iOS
。
小程序真机调试是基于小程序开发者工具的真机调试
能力和appnium
实现的。如果case使用了minium.Native的接口,则配置文件中必须配置device_desire
配置项
Android需要保证命令行能识别到手机设备
$ adb devices
List of devices attached
28fb61d0ef1c7ece device
Copy to clipboardErrorCopied
如果只有一台手机在线,那么只需要把platform
配置成Android
即可, 而如果多台设备连接到手机,配置文件需要制定设备的序列号,如:
{
"debug_mode": "debug",
"enable_app_log": false,
"platform": "Android",
"device_desire": {
"serial": "28fb61d0ef1c7ece"
}
}
Copy to clipboardErrorCopied
在我们连接真机的时候,Android手机安装微信测试的apk,有些手机在安装过程中会弹框或者输入密码,所以第一次运行的时候可能需要人为的处理
brew uninstall ideviceinstaller
brew uninstall libimobiledevice
brew install --HEAD libimobiledevice
brew link --overwrite libimobiledevice
brew install ideviceinstaller
brew link --overwrite ideviceinstaller
Copy to clipboardErrorCopied
如果没有安装过直接 brew install ideviceinstaller 即可。
当然你也可以本地编译:
git clone https://github.com/libimobiledevice/libimobiledevice.git
cd libimobiledevice
./autogen.sh --disable-openssl
make
sudo make install
Copy to clipboardErrorCopied
minium 不包含 WebDriverAgent(简称wda) 工程,请到appium/WebDriverAgent clone 最新版本,只需要简单配置两个选项即可
配置完成之后,可以用⌘+u
快捷键运行 unit test 测试 wda 是否正常运行
更加详细的配置说明请访问appium/WebDriverAgent/wiki
在用例目录下面新增一个叫config.json
的配置文件,格式如下
{
"platform": "iOS",
"device_desire":{
"wda_project_path": "/Users/sherlock/github/appium/WebDriverAgent", //自定义 wda 的路径
"device_info": {
"udid": "aee531018e668ff1aadee0889f5ebe21a2292...", //手机的 udid
"model": "iPhone XR",
"version": "12.2.5",
"name": "sherlock's iPhone"
}
}
}
Copy to clipboardErrorCopied
PS: JSON不支持注释,请把“//”以及后面的内容删掉
详细说明请看:测试配置
为了保证同一套代码在IDE,Android,IOS上运行,环境组成比较复杂,所以测试用例的运行依赖于配置文件。相关配置项说明如下表:
配置项 | 类型 | 默认值 | 说明 |
---|---|---|---|
platform | String | ide | 小程序运行的平台,可选值为:ide, Android, IOS |
project_path | String | 空 | 小程序代码的项目路径,如果配置了之后,那么需要同时配置dev_tool_path |
dev_tool_path | String | 空 | 小程序IDE cli的路径 |
enable_app_log | Boolean | True | 是否监听小程序代码返回的日志 |
enable_network_panel | Boolean | False | 是否监听所有wx.request的请求和返回,日志生成到request.log |
outputs | String | outputs | 用例运行的结果存放目录 |
debug_mode | String | info | 日志打印级别,可选:error, warn, info, debug |
close_ide | Boolean | False | 执行完一个 class 是否关闭 ide,ide 下运行不生效 |
full_reset | Boolean | False | 执行完一个 class 是否关闭 ide 和 native driver |
device_desire | Object | null | 连接手机的参数,跟手机平台有关系 |
test_port | int | 9420 | IDE监听的端口,默认为9420 |
assert_capture | Boolean | True | 在assert的时候是否截图 |
auto_relaunch | Boolean | True | 启动的时候relaunch到启动页面 |
use_push | Boolean | True | 是否自动推送远程调试 |
remote_connect_timeout | int | 180 | 远程调试连接超时时间 s |
request_timeout | int | 30 | 请求连接超时时间 s |
account_info | dict | None | 账号信息,多账号运行使用 |
mock_native_modal | dict | {} | 仅在ide上生效, mock会引起授权弹窗的方法, 使有弹窗的情况下仍能在ide上运行,具体用法请参考IDE的mock_native_modal配置项 |
mock_request | list | [] | mock网络请求, 具体用法参考mock_request配置项 |
其中 account_info
有如下两项,通过minitest -a
获取:
配置项 | 类型 | 默认值 | 说明 |
---|---|---|---|
wx_nick_name | String | None | 微信账号名称 |
open_id | String | None | 微信账号的 open_id |
其中,device_desire
跟平台有关系,不同平台配置不一样。
配置项 | 类型 | 默认值 | 说明 |
---|---|---|---|
serial | String | null | Android设备号, adb devices 查看 |
uiautomator_version | int | 1 | 底层使用的Ui Automator版本, 可选: 1 , 2 |
device_desire:
配置项 | 类型 | 默认值 | 说明 |
---|---|---|---|
wda_project_path | String | not null | 自定义 wda 的路径 |
device_info | Dict | not null | 真机信息 |
其中device_info:
配置项 | 类型 | 默认值 | 说明 |
---|---|---|---|
udid | String | not null | 手机的 uuid |
model | String | null | 机型 |
version | String | null | 系统版本 |
name | String | null | 设备名称 |
mock_native_modal:
配置项 | 类型 | 默认值 | 说明 |
---|---|---|---|
weRunData | Dict | None | 参考wx.getWeRunData 接口返回的结果信息 |
userInfo | Dict | None | 参考wx.getUserInfo 接口返回的结果信息 |
location | Dict | None | 参考wx.getLocation 和wx.chooseAddress 接口返回的结果信息 |
{
"mock_native_modal": {
"weRunData": {
"encryptedData": "123",
"iv": "456=="
},
"userInfo": {
"nickName":"test test",
"gender":1,
"language":"zh_CN",
"city":"",
"province":"",
"country":"St.Kitts and Nevis",
"avatarUrl":"https://xxxx.qq.com"
},
"location": {
"address": "广东省广州市",
"latitude": 23.0999,
"longitude": 113.3249,
"name": "腾讯微信总部"
}
}
}
Copy to clipboardErrorCopied
mock_request中每一项配置:
配置项 | 类型 | 默认值 | 说明 |
---|---|---|---|
rule | str|dict | Not None | 规则,如类型为str,则默认匹配url |
success | dict | None | 成功回调结果,与参数fail 需二选一 |
fail | str|dict | None | 失败回调结果,如类型为str,会自动填充成基础库返回格式,与参数success 需二选一 |
以下例子运行效果同App.mock_request中的例子
{
"mock_request": [
{
"rule": ".*/SendMsg\\?.*",
"success": {"data": "mock result1", "statusCode": 200}
},
{
"rule": {"url": ".*/SendMsg$"},
"success": {"data": "mock result2", "statusCode": 200}
},
{
"rule": {"url": ".*/SendMsg.*", "data": {"content": "^\\d+$"}},
"success": {"data": "mock result3", "statusCode": 200}
},
{
"rule": {"url": ".*/SendMsg.*"},
"fail": {"errMsg": "request:fail mock fail"}
},
]
}
Copy to clipboardErrorCopied
{
"debug_mode": "debug",
"enable_app_log": true,
"project_path": "/Users/sherlock/github/miniprogram-demo",
"dev_tool_path": "/Applications/wechatwebdevtools.app/Contents/MacOS/cli",
"platform": "ios",
"close_ide": true,
"test_port": 9420,
"assert_capture": true,
"use_push": true,
"auto_relaunch": true,
"remote_connect_timeout": 180,
"device_desire": {
"wda_project_path": "/Users/sherlock/.npm-global/lib/node_modules/appium/node_modules/appium-webdriveragent",
"os_type": "ios",
"device_info": {
"udid": "aee531018e668ff1aadee0889f5ebe21axxxxxe8",
"model": "iPhone XR",
"version": "12.2.5",
"name": "sherlock's iPhone"
}
}
}
minium 通过 WXSS 选择器来定位元素的,目前小程序仅支持以下的选择器:
选择器 | 样例 | 样例描述 |
---|---|---|
.class | .intro | 选择所有拥有 class="intro" 的组件 |
#id | #firstname | 选择拥有 id="firstname" 的组件 |
element | view | 选择所有 view 组件 |
element, element | view, checkbox | 选择所有文档的 view 组件和所有的 checkbox 组件 |
::after | view::after | 在 view 组件后边插入内容 |
::before | view::before | 在 view 组件前边插入内容 |
一个元素的选择器通常是以下格式组成的:
id 不能以数字开头,命名规范问题
tageName + #id + .className
这其实是三个选择器组合的结果,其中:
tagName
:类型选择器,标签名称,view、checkbox 等等,选择所有指定类型的最简单方式。id
:ID 选择器,自定义给元素的唯一 ID,使用时前面跟着 #
号,这是选择单个元素的最有效的方式。className
:类选择器,由一个点.
以及类后面的类名组成,存在多个类的时候可以以点为间隔一直拼接下去。e.g:
Copy to clipboardErrorCopied
假如要查找像上面这一个元素的话,他的选择器会像是下面这样:
view#main.page-section.page-section-gap
Copy to clipboardErrorCopied
另一种写法
view[id='main'][class='page-section page-section-gap']
Copy to clipboardErrorCopied
所以,通常我们只需要关注一个元素的 id 和 class 即可。但是有时候有的情况是,有一堆没有 id ,相同 class 的同名标签,我们没办法通过 id 或者 class 来区分了,比如我们 demo 的 input 页面:
可以自动聚焦的input
...
...
...
...
...
...
...
...
...
...
Copy to clipboardErrorCopied
我们仔细观察,虽然所有的 input 都有着同样的 class,但其实他们并非都是一模一样的,在实际测试中,我们发现绝大部分的属性都可以用来寻找。
e.g:
Copy to clipboardErrorCopied
如上,我们可以通过 type
和 placeholder
两个属性去找到这个元素。
input[type='digit']
Copy to clipboardErrorCopied
或者
input[placeholder='带小数点的数字键盘']
Copy to clipboardErrorCopied
亦或者,两者加起来
input[type='digit'][placeholder='带小数点的数字键盘']
Copy to clipboardErrorCopied
所以,具体情况具体分析,在我测试的过程中发现,bindinput
这一类绑定方法是不能用作寻路依据的。
公共库 2.10.0 之后支持
获取登录账号的 open id
2.1 先以自动化模式打开开发者工具,端口默认 9420
创建配置文件,形式如下,你需要将 open id 和 udid 替换成你自己的账号和设备,保存为 m_config.json
[{
"debug_mode": "debug",
"enable_app_log": true,
"project_path": "/Users/sherlock/github/miniprogram-demo",
"dev_tool_path": "/Applications/wechatwebdevtools.app/Contents/MacOS/cli",
"platform": "ide",
"app": "wx",
"close_ide": false,
"test_port": 9421,
"assert_capture": true,
"use_push": true,
"auto_relaunch": true,
"remote_connect_timeout": 10,
"account_info": {
"wx_nick_name": "locker",
"open_id": "o6zAJs_pwr**********aROZDjiw"
},
"device_desire": {
"wda_project_path": "/Users/sherlock/.npm-global/lib/node_modules/appium/node_modules/appium-webdriveragent",
"os_type": "ios",
"device_info": {
"udid": "aee531018e668ff1aad*************2924e8",
"model": "iPhone 6",
"version": "12.2.5",
"name": "sherlock's iPhone"
}
}
},
{
"debug_mode": "debug",
"enable_app_log": true,
"project_path": "/Users/sherlock/github/miniprogram-demo",
"dev_tool_path": "/Applications/wechatwebdevtools.app/Contents/MacOS/cli",
"platform": "ide",
"app": "wx",
"close_ide": false,
"test_port": 9422,
"assert_capture": true,
"use_push": true,
"auto_relaunch": true,
"remote_connect_timeout": 10,
"account_info": {
"wx_nick_name": "恒瑜_Sherlock",
"open_id": "o6zAJsx7zt4***********Tz7Kx10A"
},
"device_desire": {
"wda_project_path": "/Users/sherlock/.npm-global/lib/node_modules/appium/node_modules/appium-webdriveragent",
"os_type": "ios",
"device_info": {
"udid": "aee531018e668ff1***********ebe21a22924e8",
"model": "iPhone XR",
"version": "12.2.5",
"name": "sherlock's iPhone"
}
}
}]
Copy to clipboardErrorCopied
$ minitest -s suite.json -c m_config.json -g
Copy to clipboardErrorCopied
PS: 上图为了方便展示,platform 配置项都设置为 ide,真机运行只需将 platform 设置为 iOS 或者 Android,并填写好设备 udid 即可,跟之前单机真机运行的步骤一致
今天的文章就分享在这里了,关注我后续会继续更新优质的文章
最后感谢每一个认真阅读我文章的人,看着粉丝一路的上涨和关注,礼尚往来总是要有的,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走:
这些资料,对于【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴上万个测试工程师们走过最艰难的路程,希望也能帮助到你!
在我的QQ技术交流群里(技术交流和资源共享,广告勿扰)
可以自助拿走,群号:310357728群里的免费资料都是笔者十多年测试生涯的精华。还有同行大神一起交流技术哦
如果对你有一点点帮助,各位的「点赞」就是小编创作的最大动力,我们下篇文章见
在小公司“混”了2年,我只认真做了5件事,如今顺利拿到字节 Offe
去了字节跳动,才知道年薪 30w 的测试工程师有这么多?
北京35岁程序员失业,感叹:编程估计没戏了,想去卖点煎饼果子养家~
29岁转行软件测试靠谱吗?一个过来人的心路历程送给迷茫的你
同样是IT行业,测试和开发薪资真就差这么大吗?