打造一款快速高效且高度可复用的android自动化测试工具 (qq群 :608824162)
主页:
https://github.com/zhangzhao4444/Maxim
优势
高速点击,每秒 10-15 action!
多平台兼容! 同时兼容Android 5-8
轻量极简!
如何使用
adb push framework.jar monkey.jar 文件到 /sdcard
执行 adb shell CLASSPATH=/sdcard/monkey.jar:/sdcard/framework.jar exec app_process /system/bin tv.panda.test.monkey.Monkey -p com.panda.videoliveplatform --uiautomatormix --running-minutes 60
参数说明
tv.panda.test.monkey.Monkey 主调入口 无需修改
-p com.panda.videoliveplatform 待测appid
策略模式
--uiautomatormix 混合模式(70%控件解析随机点击,其余30%按原Monkey事件概率分布)
--pct-uiautomatormix n 可自定义混合模式中控件解析事件概率
--uiautomatordfs DFS深度遍历算法(优化版)(注 Android5不支持dfs)
非以上两种为原始Monkey策略
执行时长
--running-minutes 60 执行60分钟monkey
场景细粒度控制
--act-whitelist-file /sdcard/awl.strings 自定义Activity白名单
例:com.panda.videoliveplatform.activity.WelcomeActivity
com.panda.videoliveplatform.activity.SplashWakeActivity
com.panda.videoliveplatform.activity.MainFragmentActivity
com.panda.videoliveplatform.activity.LiveRoomActivity
锁定跳转只可进入其中的某个Activity
--act-blacklist-file 同上
其他参数及用法同原始Monkey
特性简介
a. 速度快 每秒10-15个Action事件
界面控件解析算法通过改造底层framework,直接使用AccessibilityNodeInfo并优化减化其调度流程,解析速度控制在50ms内,可对界面变化做快速反应。
{
val clickable = ArrayList()
collectClickable(clickable, root) //递归算法生成node树结构 ......
val node = clickable[random.nextInt(count)]
val nodeRect = Rect()
node.getBoundsInScreen(nodeRect) //选取其中某个node的 rect ,随机点击其中某point
generateClickEventAt(nodeRect, 0L)}
b. Android全平台兼容
兼容Android5,6,7,8各系列。通过反射原理动态解析各平台Api差异,使用一套逻辑兼容全系列。
{
Class> clazz = mAm.getClass();
String name = "setActivityController"; //存在差异的api
Method method = findMethod(clazz, name, android.app.IActivityController.class); //反射动态search api
if (method != null) {
......
}
method = findMethod(clazz, name, android.app.IActivityController.class, boolean.class);
if (method != null) {
......}
c. 防跳出
控件解析时获取进程推栈Top Activity,按非白即黑立即执行切回。各事件执行时按特有逻辑屏蔽掉状态栏,防止误操作。
{
......
cn = this.mDevice.mAm.getTasks(1, 0).get(0).topActivity //取top activity if (cn != null) currentPackage = cn.getPackageName()
if (!MonkeyUtils.packageFilter.isPackageValid(currentPackage!!)) { //判断非白即黑 this.mQ.clear()
this.generateActivity()
......}
d. 防休眠
休眠时自动检测并唤醒屏幕。
{
......
if (!this.mPM!!.isInteractive) { //判断处于休眠中 ......
val i = Runtime.getRuntime().exec(arrayOf("input", "keyevent", "26")).waitFor() //唤醒设备 ......}
e. 熔断机制
当事件按某个特有模式固定执行一段时间时则自动触发熔断开始自拉活,防止假死。如重复点击同一位置n秒。
private fun isBlocked(): Boolean{
val jam = true
......
val last = actionsHistory.last()
for (i in 2..30){ //重复点击n次 触发熔断
if (mVerbose > 1)
Logger.log("last action is ${actionsHistory.size-1} code = $last, action${actionsHistory.size-i} code = ${actionsHistory[actionsHistory.size-i]}")
if (last != actionsHistory[actionsHistory.size-i]){
return false
}
}
//其他熔断 .....}
f. 场景细粒度
引入Activity黑白名单,可控制限定在某些场景内。如只测试某几个相关页面。
private inner class ActivityController : IActivityController.Stub() {
override fun activityStarting(intent: Intent, pkg: String): Boolean {
var allowActivity = true
if (MonkeyUtils.activityFilter.hasValidActivitys()){
val currentActivity: String? = try {intent.component.className} catch (e:Exception){null}
if (currentActivity != null){
allowActivity = MonkeyUtils.activityFilter.checkEnteringActivity(currentActivity) //通过filter的才允许跳转 }
Logger.log("// Activity : ${currentActivity} in Intent")
}
......
}
......}
g. 随机自动输入
检测当遇到可输入模式时,按设定(ape.string)或随机输入键盘事件。如输入666或2333弹幕
随机输入 需要提前安装adbkeyboard
https://github.com/senzhk/ADBKeyBoard
{
......
val inputMethodVisbleHight = this.mDevice.mIMM!!.getInputMethodWindowVisibleHeight() //存在键盘输入栏
if (inputMethodVisbleHight <= 0) return
//注入键盘事件
try { generateRandomKeyEvents() }catch (e : Exception){ }
......}
h. 崩溃堆栈自动保存
当崩溃(crash、oom)发生时自动抓取,并存于/sdcard/crash-dump.log
{
override fun appCrashed(processName: String, pid: Int, shortMsg: String, longMsg: String, timeMillis: Long, stackTrace: String): Boolean {
......
writeDumpLog("// CRASH: $processName (pid $pid) (dump time: $dateStr)")
writeDumpLog("// Build Time: ${Build.TIME}")
writeDumpLog("// ${stackTrace.replace("\n", "\n// ")}") ....}
todo
特殊事件序列
引入GT性能测试
![]()