2.1.0 版本已经发布
百度网盘: https://pan.baidu.com/s/1bpmR3eJ
在线帮助文档: https://seveniruby.gitbooks.io/appcrawler/content/
相关文章: https://testerhome.com/search?q=appCrawler
腾讯安全部门也有使用 https://security.tencent.com/index.php/blog/msg/105
问答 QQ 群:177933995 能获取最新的内测版本和一些配置文件模板
为了表示对社区 7 月 15 号的测试大会的支持, 接下来将只允许参会同学加群咨询问题
加群请注明参会的个人姓名 大会报名连接
使用介绍
----------------
AppCrawler 2.0.0
app爬虫, 用于自动遍历测试. 支持Android和iOS, 支持真机和模拟器
帮助文档: http://seveniruby.gitbooks.io/appcrawler
移动测试技术交流: https://testerhome.com
感谢: 晓光 泉龙 杨榕 恒温 mikezhou yaming116
感谢提供商业支持的优秀公司: Keep
--------------------------------
Usage: appcrawler [options]
-a, --app <value> Android或者iOS的文件地址, 可以是网络地址, 赋值给appium的app选项
-c, --conf <value> 配置文件地址
-p, --platform <value> 平台类型android或者ios, 默认会根据app后缀名自动判断
-t, --maxTime <value> 最大运行时间. 单位为秒. 超过此值会退出. 默认最长运行3个小时
-u, --appium <value> appium的url地址
-o, --output <value> 遍历结果的保存目录. 里面会存放遍历生成的截图, 思维导图和日志
--capability k1=v1,k2=v2...
appium capability选项, 这个参数会覆盖-c指定的配置模板参数, 用于在模板配置之上的参数微调
-r, --report <value> 输出html和xml报告
--template <value> 输出代码模板
--master <value> master的diff.yml文件地址
--candidate <value> candidate环境的diff.yml文件
--diff 执行diff对比
-vv, --verbose 是否展示更多debug信息
--help
示例
appcrawler -a xueqiu.apk
appcrawler -a xueqiu.apk --capability noReset=true
appcrawler -c conf/xueqiu.json -p android -o result/
appcrawler -c xueqiu.json --capability udid=[你的udid] -a Snowball.app
appcrawler -c xueqiu.json -a Snowball.app -u 4730
appcrawler -c xueqiu.json -a Snowball.app -u http://127.0.0.1:4730/wd/hub
#启动已经安装过的app
appcrawler --capability appPackage=com.xueqiu.android,appActivity=.welcomeActivity
#从已经结束的结果中重新生成报告
appcrawler --report result/
#新老版本对比
appcrawler --candidate result/ --master pre/ --report ./
#自动生成Page Object代码模板文件
appcrawler --template PageObjectDemo.ssp --output result/
#根据wda的inspector生成测试用例代码
appcrawler --template PageObjectDemo.ssp -u http://localhost:8100
重构了一半多的代码. 提升了性能, 改进测试用例生成的方式. 更快更稳定.
所有的 action 字段都支持简单的动作和完整的 scala 编程语句, 样例如下
以前的是 MiniAppium.xxx, 新版本修改为 driver.xxx, 这个 driver 就是 selenium 的 driver
如果 appium 崩溃了 (主要是 uiautomator 的崩溃), appcrawler 会自动重启 appium 继续测试.
这样需要修改你的遍历配置, 设置为 dontStopAppOnReset: true
androidCapability:
deviceName: "192.168.0.102:5555"
appPackage: "com.gotokeep.keep"
appActivity: ".activity.SplashActivity"
dontStopAppOnReset: true
app: ""
appium: "http://127.0.0.1:4723/wd/hub"
automationName: uiautomator2
进行了更好的分类管理. 根据页面进行分类.
目前可以根据老版本的运行结果来断言新版本的老功能是否符合预期.
分为结果对比和数据对比, 降噪还没实现.
之前硬编码了使用老的 uiautomator 模式, 这次放开了 automationName, 可以支持 uiautomator2 和 macaca 了
在 automationName 处可以指定 macaca, 其他配置跟 appium 一样.
androidCapability:
deviceName: "192.168.0.102:5555"
appPackage: "com.gotokeep.keep"
appActivity: ".activity.SplashActivity"
app: ""
appium: "http://127.0.0.1:4723/wd/hub"
# automationName: uiautomator2
automationName: macaca
reuse: 3
用来判断 app 有没有崩溃, 或者点击后有没有特殊的需要注意的控件
asserts:
- given:
- //*
when: []
then:
- //*[@package="com.gotokeep.keep"]
- given:
- //*[@text="发送朋友圈"]
when: []
then:
- //*[@package="com.tencent.mm"]
比如设定了断言所有的预期结果里面, 包名都必须是 keep, 那么遇到拍照或者发朋友圈, qq 登录的地方, 就会提示错误.
可以通过断言预期结果的基本内容.
完整的自动化用例支持在 2.1.0 版本再放出来. 目前的只是 demo, 只是用来辅助自动遍历的.
testcase:
name: demo1
steps:
- when:
xpath: //*[contains(@resource-id, 'text_home_train_collection_title')]
action: driver.swipe(0.5, 0.8, 0.5, 0.2)
then: []
- when:
xpath: //*[contains(@resource-id, 'text_home_train_collection_title')]
action: driver.swipe(0.5, 0.2, 0.5, 0.8)
then: []
- when:
xpath: //*[contains(@resource-id, 'text_home_train_collection_title')]
action: tap
then:
- //*[contains(@text, "置顶")]
- when:
xpath: //*[contains(@text, '置顶')]
action: click
then:
- //*[contains(@text, "添加训练")]
- //*[contains(@text, "故意错误")]
目前为 2.0.0 版本
2.1.0 会未发布的下个版本计划
# 2.1.0 [TODO]
独立的yaml格式的自动化测试用例支持
支持从历史数据中寻找最优点击路径
支持web
支持游戏app遍历
# 2.0.0
支持macaca[完成]
失败重试[完成]
支持简单的测试用例[完成]
架构重新设计[完成]
新老版本对比报告改进[完成]
# 1.9.0
支持遍历断言[完成]
支持历史对比断言[完成]
修正不支持uiautomator2的问题[完成]
支持yaml自动化测试用例[完成]
action支持长按[完成]
重构用例生成方式[完成]
---
logLevel: "TRACE"
reportTitle: "Keep"
saveScreen: true
screenshotTimeout: 20
currentDriver: "android"
showCancel: true
tagLimitMax: 5
tagLimit:
- xpath: //*[../*[@selected='true']]
count: 12
maxTime: 10800
resultDir: ""
capability:
newCommandTimeout: 120
launchTimeout: 120000
platformVersion: ""
platformName: "Android"
autoWebview: "false"
autoLaunch: "true"
noReset: "true"
androidInstallTimeout: 180000
androidCapability:
deviceName: "192.168.0.102:5555"
appPackage: "com.gotokeep.keep"
appActivity: ".activity.SplashActivity"
dontStopAppOnReset: true
app: ""
appium: "http://127.0.0.1:4723/wd/hub"
# automationName: uiautomator2
automationName: uiautomator2
reuse: 3
# nativeWebScreenshot: "true"
defineUrl:
- //*[@selected='true' and contains(name(), 'TextView')]/@text
#- //*[contains(@resource-id, 'title')]/@text
appWhiteList:
- android
- com.shafa.market
baseUrl:
- ".*MainActivity"
- ".*SNBHomeView.*"
maxDepth: 20
headFirst: true
enterWebView: true
urlBlackList:
- .*OutdoorSummaryMap.*
- .*PersonalPage.*
- .*Training.*
- .*FriendRank.*
- .*\\.base\\.Container.*
#urlWhiteList:
#- ".*Main.*"
backButton:
- //*[contains(@resource-id, "left_button") and @clickable='true']
#defaultBackAction:
#- import sys.process._;
#- Thread.sleep(5000)
#- val name=Seq("adb", "shell", "dumpsys window windows | grep mCurrentFocus").!!.split(" ")(4).split("/")(0)
#- println(s"kill package ${name}")
#- Seq("adb", "shell", s"am force-stop ${name}").!!
#firstList:
#- //*[contains(@resource-id, "layout_picker_view_container"]
selectedList:
#android非空标签
- //*[@clickable='true']
- //*[@clickable='true']//*[contains(name(), 'Text') and string-length(@text)>0 and string-length(@text)<10 ]
#通用的button和image
- //*[@clickable='true']//*[contains(name(), 'Button')]
- //*[@clickable='true']//*[contains(name(), 'Image')]
#todo:如果多个规则都包含相同控件, 如何排序
#处于选中状态的同级控件最后点击
lastList:
- //*[../*[@selected='true']]
- //*[../../*/*[@selected='true']]
- //*[../../*/*[@selected='true'] and contains(@resource-id, 'tab_')]
- //*[contains(name(), "HorizontalScrollView")]
- //*[@resource-id='com.gotokeep.keep:id/layout_bottom']
blackList:
- ".*\\.[0-9].*"
- ".*[0-9]{2,}.*"
- //*[contains(@resource-id, "wrapper_in_custom_title_bar")]//*[contains(@resource-id, "right_button")]
- //*[contains(@resource-id, "share")]
- //*[contains(@text, "开始第")]
- //*[contains(@resource-id, "lock")]
- //*[contains(@text, "举报")]
triggerActions:
- xpath: //*[contains(@resource-id, "layout_picker_view_container")]//*[@text="确定"]
- xpath: //*[contains(@resource-id, "content-wrapper_dialog")]//*[@text="不发了"]
- xpath: //*[@text="拒绝"]
- xpath: //*[@text="放弃"]
- xpath: //*[@text="结束训练"]
- xpath: //*[contains(@resource-id, "quit_confirm_button")]//*[contains(@text, "确定")]
- xpath: //*[contains(@resource-id, "layout_right_second_button")]//*[contains(@resource-id, "right_second_button")]
action: yoga
times: 1
asserts:
- given:
- //*
then:
- //*[@package="com.gotokeep.keep"]
- given:
- //*[@text="胸部"]
then:
- //*[contains(@text, "离心俯卧撑")]
testcase:
name: demo1
steps:
- when:
xpath: //*[contains(@resource-id, 'text_home_train_collection_title')]
action: driver.swipe(0.5, 0.8, 0.5, 0.2)
then: []
- when:
xpath: //*[contains(@resource-id, 'text_home_train_collection_title')]
action: driver.swipe(0.5, 0.2, 0.5, 0.8)
then: []
- when:
xpath: //*[contains(@resource-id, 'text_home_train_collection_title')]
action: tap
then:
- //*[contains(@text, "置顶")]
- when:
xpath: //*[contains(@text, '置顶')]
action: click
then:
- //*[contains(@text, "添加训练")]
- //*[contains(@text, "故意错误")]
#所有view的叶子节点 一般表示游戏
#- action: monkey
# xpath: //android.view.View[not(*) and contains(@bounds, "[0,0]") ]
# times: 20
#startupActions:
#- println(driver)
#beforeElementAction:
#- xpath: //*[@resource-id="com.shafa.market:id/nav"]//android.widget.TextView
# action: MiniAppium.event(21)
#- Thread.sleep(3000)
#- println(driver.getPageSource())
#afterElementAction:
#- println(driver)
#afterUrlFinished:
#- monkey()