大家好,我是小码哥,今天整理了一份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开发了很多小程序相关的测试工具,这些工具都有以下缺点:
- 只能在Android端上运行。小程序实际是一个跨平台的产品(IDE,Android和IOS),测试的平台覆盖不足。
- 兼容性问题。小程序底层运行的内核多样化(x5,原生webview内核等等),对应的调试端口不一定能够打开。
- 只能做UI相关的测试。小程序架构上分为渲染层和逻辑层,这些框架对于逻辑层上面的测试限制较大。
而 minium
除了以上缺点都没有之外,还支持以下更多特性:
特性
- 支持一套脚本,iOS & Android & 模拟器,三端运行
- 提供丰富的页面跳转方式,看不到也能去得到
- 可以获取和设置小程序页面数据,让测试不止点点点
- 可以直接触发小程序元素绑定事件
- 支持往 AppSerive 注入代码片段执行
- 可以调用部分 wx 对象上的接口
- 支持 Mock wx 对象上的接口
- 支持 Hook wx 对象上的接口
- 通过 suite 方式管理用例,config 管理运行设备
- ...
暂不支持
- H5页面的调试
- 插件内wx接口调用
快速开始
运行环境
- Python 3.8及以上
- 微信开发者工具 最新版本,并打开安全模式:
设置 -> 安全设置 -> 服务端口: 打开
- 微信 >= 7.0.7 (确认微信公共库版本 >= 2.7.3即可)
必要的知识
本框架与开发者工具有强关联,如果你之前对开发者工具没有基本的了解,可以点击下面的链接了解一些必要的知识:
- Python3 官网文档 简单教程
- 开发者工具
- 开发者工具的界面
- 真机调试
- 命令行调用
安装
下载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还集成了测试框架,给你提供更多的测试能力。详情见测试进阶
常见问题排查
- cli环境问题,一般报错如下:
MiniConfigError: dev_tool_path: /Applications/wechatwebdevtools.app/Contents/MacOS/cli not exists
解决方法:
- 请参考开发者工具的命令行工具排查环境问题。
- 在minium配置文件中配置
dev_tool_path
路径或实例化的时候加上dev_tool_path
选项。参考测试配置或例子
检查方法:
"path/to/cli" auto --project "path/to/project" --auto-port 9420
Copy to clipboardErrorCopied
看到类似下图的log并能正确打开开发者工具即可。
- 登录开发者工具的帐号没有该项目的开发者权限,一般报错如下:
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可以大大降低小程序测试成本。如何快速使用测试框架进行测试,可参考例子
- 开发者工具->详情->本地设置选择最新版本的调试基础库(公共库)
-
测试进阶
-
framework
minium提供一个基于unittest封装好的测试框架,利用这个简单的框架对小程序测试可以起到事半功倍的效果。
测试基类Minitest会根据测试配置进行测试,minitest向上继承了
unittest.TestCase
,并做了以下改动: - 加载读取测试配置
- 在合适的时机初始化minium.Minium、minium.App和minium.Native
- 根据配置打开IDE,拉起小程序项目和或自动打开真机调试
- 拦截assert调用,记录检验结果
- 记录运行时数据和截图,用于测试报告生成
一个简单例子
目录结构
.
├── test
│ └── __init__.py
│ └── first_test.py
└── config.json
Copy to clipboardErrorCopied
编写第一个case
编辑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
更多配置信息请参考测试配置
运行case
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
即可查看报告,如图:
Class minium.MiniTest
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
来加载用例,相关的参数说明如下:
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 clipboardErrorCopiedsuite.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
更多命令行参数请参考命令行工具
测试结果
每条用例的测试结果我们会存放到一个目录里面,里面包含:
- 包含用例执行信息的json文件
- 用例运行中的截图
- 用例运行中的日志
- 小程序运行中的日志
基于这些数据可以生成测试报告,也可以做一些存档的事情。
测试报告
根据用例的执行结果,我们基于Vue和element提供一个简洁的测试报告:例子。
报告生成有2种方式:
- 执行用例的时候加上
-g
参数 - 针对已经生成的用例结果目录
minireport input_path output_path
Copy to clipboardErrorCopiedoutput_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
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,有些手机在安装过程中会弹框或者输入密码,所以第一次运行的时候可能需要人为的处理
IOS
安装 libmobiledevice
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
配置 WebDriverAgent
minium 不包含 WebDriverAgent(简称wda) 工程,请到appium/WebDriverAgent clone 最新版本,只需要简单配置两个选项即可
配置完成之后,可以用⌘+u
快捷键运行 unit test 测试 wda 是否正常运行
更加详细的配置说明请访问appium/WebDriverAgent/wiki
配置测试 config.json
在用例目录下面新增一个叫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
跟平台有关系,不同平台配置不一样。
Android的device_desire配置项
配置项 | 类型 | 默认值 | 说明 |
---|---|---|---|
serial | String | null | Android设备号, adb devices 查看 |
uiautomator_version | int | 1 | 底层使用的Ui Automator版本, 可选: 1 , 2 |
IOS的device_desire配置项
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 | 设备名称 |
IDE的mock_native_modal配置项
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配置项
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:
<view id="main" class="page-section page-section-gap" style="text-align: center;"></view>
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 页面:
<view class="page-body">
<view class="page-section">
<view class="weui-cells__title">可以自动聚焦的input</view>
<view class="weui-cells weui-cells_after-title">
<view class="weui-cell weui-cell_input">
<input class="weui-input" auto-focus placeholder="将会获取焦点" bindinput="bindKeyInput"/>
...
<input class="weui-input" maxlength="10" placeholder="最大输入长度为10" />
...
<input class="weui-input" maxlength="10" bindinput="bindKeyInput" placeholder="输入同步到view中"/>
...
<input class="weui-input" bindinput="bindReplaceInput" placeholder="连续的两个1会变成2" />
...
<input class="weui-input" bindinput="bindHideKeyboard" placeholder="输入123自动收起键盘" />
...
<input class="weui-input" type="number" placeholder="这是一个数字输入框" />
...
<input class="weui-input" password type="text" placeholder="这是一个密码输入框" />
...
<input class="weui-input" type="digit" placeholder="带小数点的数字键盘"/>
...
<input class="weui-input" type="idcard" placeholder="身份证输入键盘" />
...
<input class="weui-input" placeholder-style="color:#F76260" placeholder="占位符字体是红色的" />
...
Copy to clipboardErrorCopied
我们仔细观察,虽然所有的 input 都有着同样的 class,但其实他们并非都是一模一样的,在实际测试中,我们发现绝大部分的属性都可以用来寻找。
e.g:
<input class="weui-input" type="digit" placeholder="带小数点的数字键盘"/>
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
2.2 minitest -a 获取 open id
-
创建配置文件,形式如下,你需要将 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行业,测试和开发薪资真就差这么大吗?