iOS 测试 NewLLDebugTool——ios monkey 保活

haleli · July 13, 2019 · Last by haleli replied at July 14, 2019 · 987 hits

NewLLDebugTool里面实现了一个智能monkey,现在已经支持快速遍历算法和随机遍历算法,因为monkey是集成在app里面,如果app发生crash(如果开启fuzzy功能,很容易发生crash),那么如何重新拉起app,继续运行呢?

app自己本身肯定无法拉起自己,肯定需要外力进行拉起,我自己调研有两种可行的方案:
1、通过私有api进行拉起,使用的私有api LSApplicationWorkspace,大体代码如下所示:

+(BOOL)isOpenApp:(NSString*)appIdentifierName
{
Class LSApplicationWorkspace_class = objc_getClass("LSApplicationWorkspace");
NSObject* workspace = [LSApplicationWorkspace_class performSelector:@selector(defaultWorkspace)];
BOOL isOpenApp = [workspace performSelector:@selector(openApplicationWithBundleID:) withObject:appIdentifierName];

return isOpenApp;
}

这种方案最终我放弃了,主要考虑以下几点:1、私有api,顾名思义是苹果不允许使用的api,很可能在苹果的后续版本更新中就无法使用了,从而导致这种保活方式的可兼容性很差; 2、可扩展能力不强,如果后续我们想接入持续集成(未来的趋势),那必定需要定时或者ci的时候拉去最新的安装包跑monkey,很明显自动拉取最新包并安装到手机上,是通过私有api完成不了的,如果能完成,ios全家桶了解一下。

2、方案二也是现在我采用的方式,通过ios自带的ui自动化框架xctest进行保活。xctest里面的XCUIApplication可以检查当前app的状态是否激活,如果未激活可以拉起app,大体代码如下所示:

public func addXCTestCheckCurrentApp(interval:Int, application:XCUIApplication) {
addCheck(interval:interval){ [weak self] in
let work = DispatchWorkItem(qos:.userInteractive){
if (application.state != XCUIApplication.State.runningForeground){
application.activate()
self?.sleep(5)
}
}
DispatchQueue.main.async(execute:work)
}
}

工程也已经开源,开源地址:MonkeyRunner,和monkey配合使用,效果更好。效果如下所示:

中间触发了一次预先写好的crash,app闪退,但是被xctest重新拉起,monkey继续运行,如果我们想要停止monkey,只需要摇一摇手机停止monkey即可。

最佳回复

monkey集成到app里面,另外的monkeyrunner用iOS自带的UITESTS作为执行器运行monkey,起初为啥不直接在UITEST里写monkey相关的逻辑呢

haleli 回复

1、虽然弹层页面会获取到遮挡的页面元素,我们应该想办法过滤掉不可视的元素,这里也是有办法用微小的耗时方式过滤掉不可视的UI元素的,最后还是对于元素的精准识别探讨吧
2、XCUITEST是可以拿到屏幕外的cell或者其他控件类型的元素,视频中有对屏幕之外的元素进行测试的演示,无论元素在横向或是纵向,都是可以计算的方式自动跟踪定位元素的
3、pickview等自定义视图的非触点的控件来看,也是通过配置化的方式来做,还没想到更好的方式
4、cocos 还是不熟悉,这里面就不探讨了,后续用我原先的工具试跑下看效果,熟悉下
5、忙过这阵子也会开源出来的

共收到 6 条回复 时间 点赞

monkey集成到app里面,另外的monkeyrunner用iOS自带的UITESTS作为执行器运行monkey,起初为啥不直接在UITEST里写monkey相关的逻辑呢

haleli #2 · July 14, 2019 作者

你这个问题挺好的,我们也在内部讨论了好多次,现在回答一下:

基于xctest版的智能monkey,我们也有开发过,但是问题也很明显,简单列举几条,比如说无法做到精确的控件识别,例如被遮挡或者无意义的控件也会被识别出来,无法细腻的控件操作,例如对于pickview会被识别成otherelment,对于tableviewcell只能查找出屏幕内的。

如果基于KIF实现智能monkey,是可以将我现在的这套执行ui的逻辑的那一部分提取出来的,但是侵入代码是必不可少的,比如控件树的获取,比如要hook代码里面的accessbility(KIF是基于accessbility操作ui的)、还有外围的操作,比如js error的捕获、提单、性能的上报等操作(只实现一个monkey是没有啥作用的,monkey只是一种ui执行的手段),比如集成到sdk里面的http/https mock实现fuzzy测试。

还有一个最重要的原因就是我本身负责的项目是基于cocos开发(一个游戏引擎)的,我要实现cocos monkey在xctest是无法实现的,必须要在代码里面实现monkey,这个我就不仔细展开了。

写了这么多,啰哩啰嗦的
总结:
基于xctest实现智能monkey,我这边出现的问题很多,坑也很多,不建议
基于kif实现智能monkey,你如果实现了的话,记得回复一下我这个帖子,我也学习一下😁 ,多交流

值得交流下,看了你写的侵入性的Monkey,无法做到精确的控件识别,应该是Monkey对于元素的精准识别还有提升的空间吧
1、用XCUITEST最重要是为了省事,一套代码兼容Native、WebView、RN等跨平台页面,对外无侵入性接入
2、Crash捕获、网络数据(proxy或mock)、性能监控、统计覆盖率,交给集成到客户端的SDK做些可测性改进,日志相关的回捞SDK的日志显示在报表上,场景构造相关的外部修改下数据。还有项目用cocos开发,也就是游戏相关的Monkey测试,归类为跨平台页面,一般是集成到iOS客户端上,我都会想办法对跨平台的页面做些可测性改进,这里需要具体分析,例如RN页面多个小UI组件会嵌套到一个大UI组件里,无法识别小UI组件就需要让研发在底层的RN框架里加上Accessibility辅助功能标签;Crash捕获、性能监控、日志相关的只要做的到位也是可以用黑盒的方式做部分实现的
3、获取控件树,无论是侵入性XCTEST方式或是非侵入性XCUITEST的Accessibility辅助功能都是用来提取页面控件树,最显著的区别在于使用XCUITEST在loadMore功能的页面获取source控件树耗时相当长,还容易出现非正常的意外崩溃,不过最后这些问题也都解决了,提取每个页面的控件树只需要0.3秒左右,极个别页面最慢也不会超过10秒
4、最后还是建议你抽出代码,提取部分插桩能够用指令下发UI操作即可,离智能也会更近一些吧
5、我也有一段跟你相似写Monkey的经历,试过用XCUITEST无侵入性写的效果,录了一段App视频效果验收: https://pan.baidu.com/s/1wYc_ZETUICzSDa71fHzRrA#list/path=%2F

haleli #4 · July 14, 2019 作者

第二点不讨论,Crash捕获、网络数据(proxy或mock)、性能监控、统计覆盖率,交给集成到客户端的SDK做些可测性改进。这个可以使用其他的sdk,因为我也是集成的开源的相关的sdk,后续有时间会以插件的方式进行改进。

第一点:获取控件树,举个例子,比如说界面有一个弹窗,遮挡了下面的界面,就不应该获取被遮挡的界面,xctest获取的控件树是可以将遮挡和被遮挡的界面都获取到的,这个就会导致如果点击被遮挡的控件,其实点击的是它的上层控件,想点击的和被点击的不是同一个控件,导致整个算法记录的跳转关系错乱。

比如说有一个tableview,里面有很多的tableviewcell是在屏幕外,xctest是无法获取到屏幕外cell的控件,这个就会导致xctest是无法点击到屏幕外的cell,就不会遍历整个app的控件。

第二点:cocos monkey,cocos是游戏引擎,和rnn不一样,是使用js写的,如果想要获取js的控件,需要注入我们的一个写好的脚本,才可以拿到cocos的控件。具体代码可以参考这个脚本:https://github.com/didiaodanding/NewLLDebugTool/blob/master/NewLLDebugTool/js/monkey_driver.js

第三点:对于控件的操作,比如说对于一个pickview的组件,在xctest里拿到的是otherelement,就没有办法对pickview做选取的操作,可能只会对其发送一个点击操作,实际上xctest里面拿到的大多数都是otherelement,也只能对其发送一个点击操作。

基于xctest的智能monkey,我们也有开发,如果可以的话,可以把你的代码给我开个权限吗,我读一读就应该了解了

haleli 回复

1、虽然弹层页面会获取到遮挡的页面元素,我们应该想办法过滤掉不可视的元素,这里也是有办法用微小的耗时方式过滤掉不可视的UI元素的,最后还是对于元素的精准识别探讨吧
2、XCUITEST是可以拿到屏幕外的cell或者其他控件类型的元素,视频中有对屏幕之外的元素进行测试的演示,无论元素在横向或是纵向,都是可以计算的方式自动跟踪定位元素的
3、pickview等自定义视图的非触点的控件来看,也是通过配置化的方式来做,还没想到更好的方式
4、cocos 还是不熟悉,这里面就不探讨了,后续用我原先的工具试跑下看效果,熟悉下
5、忙过这阵子也会开源出来的

haleli #6 · July 14, 2019 作者
ltyd5788 回复

嗯嗯,如果可以把我提出的问题解决掉,是一个很好的解决方案,期待开源

需要 Sign In 后方可回复, 如果你还没有账号请点击这里 Sign Up