美文网首页程序员
Android Espresso AppNotIdleExcep

Android Espresso AppNotIdleExcep

作者: H3c | 来源:发表于2018-05-10 23:44 被阅读141次

最近在研究安卓单元测试,看到官方推荐用Espresso做UI层面的测试,就简单用了下。虽然Espresso很简单,但是适配到真实项目中还是走了不少弯路,踩了不少坑的。这里记录一下:

  1. 由于项目开发的比较早,是传统的Eclipse工程转AndroidStudio工程的,因此项目结构还是传统的Eclipse工程结构,主代码都在跟目录的src文件夹下。这种情况其实很难加入测试用例进工程,要知道Android测试分为两种,即Test和AndroidTest,一个是用来测Java的,一个是用来测Android依赖的,例如测UI。除了文件目录不同之外在Gradle中的引用配置也不相同,如果没有配置好就会出现明明引入了第三方包,但是怎么也找不到的情况。而且需要在gradle中手动配置test和AndroidTest的路径,例如:
 sourceSets {
        main {
            manifest.srcFile 'AndroidManifest.xml'
            java.srcDirs = ['src']
            resources.srcDirs = ['src']
            aidl.srcDirs = ['src']
            renderscript.srcDirs = ['src']
            res.srcDirs = ['res']
            assets.srcDirs = ['assets']
        }

       androidTest{
            java.srcDirs = ['androidTest/src']
        }

        test{
            java.srcDirs = ['test/src']
        }
    }

这样配置之后工程就知道test的路径和AndroidTest的路径对应在哪里了。但是即便这样配置没问题,代码也能跑通,之后却会遇到各种各样奇怪的问题。这里不详细描述了,我反正在这里踩了两天的坑之后决定放弃了。于是我把工程整体迁移到了新的AndroidStudio结构下,即主代码在app文件夹下,迁移完成之后关于之前遇到的测试的坑全部解决了。因此建议想做单元测试的并且用Eclipse老版结构工程的尽早修改为新AS结构,可以少走不少弯路!

  1. 改为AS标准工程结构之后单元测试的坑是被填了,但是莫名其妙的跑出来性能问题。之前旧版工程开启主页Activity的时候很快,几乎是秒开。新工程开启主页Activity竟然会白屏1~2s,严重的时候2~3s。甚是奇怪。抛开首页实现逻辑问题不谈,仅仅修改工程结构竟然会导致加载性能的退后简直让人捉摸不透。最终的解决办法是UI分阶段延迟加载。

  2. 一切准备工作完成之后,本以为踩坑三天的我可以愉快的玩耍一下了,却遇到了各种Espresso水土不服,不能正常运行,Loading速度极慢之后还报错了,说AppNotIdleException。再次吐槽一下,估计国内国外做安卓单元测试的人很少,这方面的资料真是少之又少,而且都是你抄我我抄你不说,绝大多数都是讲的介绍和入门,没有什么实战经验。即便是官方文档也只是简单粗略的介绍一番。
    首先推荐看Google官方的demo,地址:https://github.com/googlesamples/android-testing
    这玩意跑在手机上贼流畅,而且AndroidStudio中直接支持Record Espresso Test。通常情况下大家直接用AS的RET功能不会遇到问题,即便是遇到问题,通过看Google官方的Demo也能解决了。
    但是我就是遇到了AppNotIdleException问题。在网上搜了一圈之后也没找到解决的办法,遇到这个问题的人通常都是由于自己写的测试用例有问题,而我排除了这个原因。最后又折腾了2天准备放弃的时候看到了这个:https://groups.google.com/forum/#!topic/android-test-kit-discuss/s9hsoZ9XdFc
    后来查资料才知道原来Espresso为了保证线程安全,会等所有AsyncTask任务全部执行完了之后才执行。如果这个等待时间超过了60s就会报AppNotIdleException。这个时候找到没有执行完的AsyncTask任务就好了。

private void dumpThreads() {
        int activeCount = Thread.activeCount();
        Thread[] threads = new Thread[activeCount];
        Thread.enumerate(threads);
        for (Thread thread : threads) {
            if("RUNNABLE".equals(thread.getState().toString()) && thread.getName().startsWith("AsyncTask")) {
                LogHelper.e("H3c", thread.getName() + ": " + thread.getState() + "=" + "RUNNABLE".equals(thread.getState().toString()));
                for (StackTraceElement stackTraceElement : thread.getStackTrace()) {
                    LogHelper.e("H3c", "VVV:" + stackTraceElement);
                }
            }
        }
    }

通过这段代码,可以输出所有正在运行的AsyncTask,通过日志找到没有结束的任务。我跟上面哪个链接中的兄弟一样,遇到的是Facebook创建的某个AsyncTask一直在运行导致的,最终我开了翻墙工具之后一切正常了。
总的来说,就是遇到AppNotIdleException问题之后,先排查代码是否写错了,如果不是代码问题,可能就跟我遇到的是一样的问题了,用上面的方法找到正在运行的AsyncTask,然后结束掉就OK了。

此文献给所有用Espresso踩坑的人。

相关文章

网友评论

    本文标题:Android Espresso AppNotIdleExcep

    本文链接:https://www.haomeiwen.com/subject/iyhxdftx.html