Appetizer 字节码插桩监控 + 自动遍历的 Android 自动化测试实战 —— 开源 Bilibili 客户端

AppetizerIO · 2017年04月01日 · 最后由 回复于 2018年12月12日 · 2172 次阅读
本帖已被设为精华帖!

背景

Android 应用的自动遍历,能够全自动的走遍整个被测试应用的所有层级页面,在一定程度上做到取代手动点击测试。但是在自动遍历的过程中,收集到的数据十分有限。

如果结合自动遍历与监控,同时多台设备多次遍历,就能够收集到海量的数据,包括 App 图片解码速度,各个页面的流量开销,CPU和堆内存占用等,对这些信息进行过滤,可以得到有价值的性能分析报告。

本文对开源 bilibili 客户端进行测试,该客户端使用了 retrofit,Rx系列,butterknife 等热门三方库,能够正常播放 Bilibili 主站视频,还包括一些功能性页面,是一个和商用 App 接近的开源项目。

工具选择

字节码插桩监控工具使用了 Appetizer 质量监控,使用 Appetizer 上传 bilibili 客户端的 APK 文件,在服务端进行字节码插桩后,下载到本地,在手机上安装。

自动遍历使用了 AppCrawler,配置文件中对 bilibili 的登录页面进行简单的配置后,便可以自动化的遍历整个 App。

Appetizer 插桩质量监控基本流程如下图:

在自动测试流程中使用 AppCrawler,在自动化遍历的同时,扩展出了自动截图功能,结合底层数据和UI截图,能获取更多信息。

实战步骤

步骤一:Appetizer 质量监控插桩

参考该教程。打开 Appetizer 客户端,登录后选择“质量监控”,点击“插桩APK文件”,等待被插桩的 APK 文件下载到本地。

或者使用命令行版的 Appetizer 质量监控客户端,依次执行 login, process 操作得到被插桩的 APK 文件。

步骤二:AppCrawler 自动遍历

根据 AppCrawler 的教程,安装好相关的依赖。由于 bilibili 客户端的第一个页面是登录页面,无法通过自动遍历跳过,需要单独配置,剩余页面都可以自动遍历。

triggerActions:
- action: "azard"
xpath: "//*[@contains(name(), "请输入您的哔哩哔哩账号")]"
times: 0
- action: "xxx"
xpath: "//*[@contains(name(), "请输入您的密码")]"
times: 0
- action: "click"
xpath: "//*[@contains(name(), "登录")]"
times: 0

=============一台古老 Nexus5 自动遍历20分钟的分割线=============
=============一台古老 Nexus5 自动遍历20分钟的分割线=============
=============一台古老 Nexus5 自动遍历20分钟的分割线=============

报表一:AppCrawler 自动遍历报表

AppCrawler 在自动遍历结束后会得到一个文件夹,有一个网页可视化的报表。从报表上可以看到一台设备运行了108个 Activity 页面,实测大概20分钟左右,H5 页面也会进行一定程度的遍历但报表不会抓取具体信息。

同时,AppCrawler 在每次点击操作前后都会进行截图,方便查看具体渲染的行为状态。

报表二:Appetizer 质量监控插桩报表

在自动化遍历结束后,通过 Appetizer 客户端或 Appetizer 质量监控命令行客户端,将设备上的质量监控log 上传服务端进行深度分析,得到 json 格式的报表,报表可以使用 Appetizer 客户端打开进行可视化。

可以看到 Appetizer 质量监控抓取到了若干问题,包括数个高延迟,可缓存的建议,一个HTTP错误,若干耗时操作和性能问题。

点击HTTP错误,可以看到具体的 HTTP 错误内容,以及调用该 HTTP 请求时的函数堆栈。

在笔者实战测试的过程中,抓取到一个控指针错误并导致 bilibili 客户端崩溃,Appetizer 质量监控抓取到了该错误,并且包含函数堆栈和当前时刻的内存占用。

点击分享按钮可以自动将问题生成 markdown 格式的 issue,发布到 GitHub 上。

该 issue 得到了开发者的确认,是由于 HTTP 调用可能返回空数据,导致渲染出错造成的。

总结

通过结合 Appetizer 质量监控插桩,和 AppCrawler 自动化遍历,可以大幅度减少手动测试的工作量,并且抓取到需要底层数据,实现对 App 更深度的测试分析。

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
共收到 17 条回复 时间 点赞

这个很棒

恒温 将本帖设为了精华贴 04月01日 13:16

赞,必须赞。

实践是检验真理的唯一标准,赞

大部分功能都可以一键完成,用户体验很赞呀~

不错不错

—— 来自TesterHome官方 安卓客户端

AppetizerIO Appetizer 基于字节码插桩的质量监控 中提及了此贴 04月01日 19:06

赞,Appetizer 和AppCrawler的完美使用结合

请更新个人资料中的微信和支付宝的打赏二维码,用于精华帖打赏

triggerActions:

  • action: "azard" xpath: "//*[@contains(name(), "请输入您的哔哩哔哩账号")]" times: 0
  • action: "xxx" xpath: "//*[@contains(name(), "请输入您的密码")]" times: 0
  • action: "click" xpath: "//*[@contains(name(), "登录")]" times: 0

你这个是写到congfig文件里么 还是怎么操作 能够让他登录

这个AppCrawler 的功能, 可以参考这里https://testerhome.com/topics/node83

老哥稳

好像不能捕获post请求

赵欢 回复

加群来讨论下: 467889502

mark,感谢分享

感谢分享

Driver info: driver.version: AndroidDriver
at io.appium.java_client.remote.AppiumCommandExecutor.lambda$2(AppiumCommandExecutor.java:101)
at java.util.Optional.orElseGet(Unknown Source)
at io.appium.java_client.remote.AppiumCommandExecutor.execute(AppiumCommandExecutor.java:100)
at org.openqa.selenium.remote.RemoteWebDriver.execute(RemoteWebDriver.java:586)
at io.appium.java_client.DefaultGenericMobileDriver.execute(DefaultGenericMobileDriver.java:42)
at io.appium.java_client.AppiumDriver.execute(AppiumDriver.java:1)
at io.appium.java_client.android.AndroidDriver.execute(AndroidDriver.java:1)
at org.openqa.selenium.remote.RemoteWebDriver.startSession(RemoteWebDriver.java:217)
at org.openqa.selenium.remote.RemoteWebDriver.(RemoteWebDriver.java:140)
at io.appium.java_client.DefaultGenericMobileDriver.(DefaultGenericMobileDriver.java:38)
at io.appium.java_client.AppiumDriver.(AppiumDriver.java:83)
at io.appium.java_client.AppiumDriver.(AppiumDriver.java:93)
at io.appium.java_client.android.AndroidDriver.(AndroidDriver.java:72)
at com.testerhome.appcrawler.driver.AppiumClient.appium(AppiumClient.scala:163)
at com.testerhome.appcrawler.driver.AppiumClient.(AppiumClient.scala:39)
at com.testerhome.appcrawler.Crawler.setupAppium(Crawler.scala:263)
at com.testerhome.appcrawler.Crawler.start(Crawler.scala:133)
at com.testerhome.appcrawler.AppCrawler$.startCrawl(AppCrawler.scala:344)
at com.testerhome.appcrawler.AppCrawler$.parseParams(AppCrawler.scala:312)
at com.testerhome.appcrawler.AppCrawler$.main(AppCrawler.scala:92)
at com.testerhome.appcrawler.AppCrawler.main(AppCrawler.scala)
Caused by: java.net.ConnectException: Connection refused: connect
at java.net.DualStackPlainSocketImpl.waitForConnect(Native Method)
at java.net.DualStackPlainSocketImpl.socketConnect(Unknown Source)
at java.net.AbstractPlainSocketImpl.doConnect(Unknown Source)
at java.net.AbstractPlainSocketImpl.connectToAddress(Unknown Source)
at java.net.AbstractPlainSocketImpl.connect(Unknown Source)
at java.net.PlainSocketImpl.connect(Unknown Source)
at java.net.SocksSocketImpl.connect(Unknown Source)
at java.net.Socket.connect(Unknown Source)
at org.apache.http.conn.socket.PlainConnectionSocketFactory.connectSocket(PlainConnectionSocketFactory.java:75)
at org.apache.http.impl.conn.DefaultHttpClientConnectionOperator.connect(DefaultHttpClientConnectionOperator.java:142)
at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:359)
at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:381)
at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:237)
at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:185)
at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:89)
at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:111)
at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:185)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:72)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:56)
at org.openqa.selenium.remote.internal.ApacheHttpClient.fallBackExecute(ApacheHttpClient.java:138)
at org.openqa.selenium.remote.internal.ApacheHttpClient.execute(ApacheHttpClient.java:86)
at org.openqa.selenium.remote.ProtocolHandshake.createSession(ProtocolHandshake.java:337)
at org.openqa.selenium.remote.ProtocolHandshake.createSession(ProtocolHandshake.java:136)
at org.openqa.selenium.remote.HttpCommandExecutor.execute(HttpCommandExecutor.java:142)
at io.appium.java_client.remote.AppiumCommandExecutor.execute(AppiumCommandExecutor.java:89)
... 18 more

大神们,菜鸟请教一个问题,就是执行appcrawler时出现上面的报错信息,这是怎么回事呢

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册