Android自动化测试Espresso+UIAutomator故障总结

1、引入espresso时报错,hamcrest等包无法解析

原因:espresso版本与annotation版本不兼容,

解决:引用espresso与annotation是注意版本号,可以看google官方:https://github.com/googlesamples/android-testing

2、报告empty test

原因:TestRunner设置错误

解决:gradle:

android

{

defaultConfig

{

instrumentationRunner  "android.support.test.runner.AndroidJUnitRunner"//注意不是AndroidJunit4

}

}


TestClass:

@Runwith(AndroidJunit4.class)

public class TestClass

{

@Test

public void testClass()

{

}

}


configuration:

specify instrumentationRunner :

AndroidJunitRunner //注意不是AndroidJunit4


3、使用ActivityInstrumentationTestCase2是报告No Activity Found

原因:setup仅仅覆写,没有改注解

方法:

    @Before//添加before注解
    @Override
    public void setUp() throws Exception //protected改public
    {
        super.setUp();
        injectInstrumentation(InstrumentationRegistry.getInstrumentation());
        getActivity();
    }


4,、automator运行是需要依赖于apk的,也就是和apk在同一个进程:在automator中获取包名时是apk的包名,context获取进程也是当前apk的进程

所以如果在automator所在apk和测试apk相同时,使用命令关闭测试apk时会导致测试线程崩溃,同样在ui线程中如果有system.exit(0)则同样会造成进程退出,测试崩溃

5、espresso需要依赖源代码,如果我在源代码所在工程上新建module,则需要将application所在module作为library,需要修改gradle改为apply plugin ‘com.android.application’,并且删除applicationid。但是这样会导致application不能直接运行安装。

6、针对上述两个问题,我能想到的办法是将测试用例分到两个module中,ui代码中放不需要测试退出的代码,新建module中放置剩余代码


7、espresso官方文档已经说明,espresso在内部已经做了同步处理,说详细点,也就是espresso会等待UI线程的消息队列为空闲时才会执行测试线程,当然还会等待所有AsyncTask执行完。就第一种情况而言,当所处页面在不停的发消息刷新页面时(有人说要求间隔在50ms内),则测试线程会被挂起,挂起60s还没执行则会导致异常

AppNotIdleException

好的办法是使用automator获取控件替代


8、还是针对espresso和uiautomator混合使用的问题,如果需要将两个测试框架放一起,有要求能测试关闭app,则需要新建一个module放置测试代码,然后将application module作为library使用,这里如果用到androidannotation的画需要将注解使用方式转换

只是需要将原来的 R.资源.资源名的方式 换成使用resName的方式即可

这样就在library 项目中使用AA 了

引用:http://blog.csdn.net/soslinken/article/details/44672391

引用:https://github.com/androidannotations/androidannotations/wiki/Library-projects

9、和8类似的问题,将application改为library后使用switch(id)会出现resource ids cannot be used,因为资源id作为library时会变为非final,此时不能用与switch ,通用改法是改为ifelse

10、为了解决espresso和uiautomator混合使用的问题,还有一种办法,可以使用espresso在非源码下使用

引用:http://blog.csdn.net/shandong_chu/article/details/47280255,可以看出博主是从robotium中拷过来的

经过测试发现不能通过反射实例化对象,猜测不在同一包下的原因,但是即使把测试包的包名改成和待测试apk包名一样,运行测试时会出现待测试apk被卸载,测试包的apk被安装的情况,导致依然无法通过反射找到activity

运行Instrumentation测试步骤:

$ adb push E:\workhome\libgdx\androidstudio\MyApplicationTest\apptest\build\outputs\apk\apptest-debug.apk /data/local/tmp/com.mystudiotest.myapplicationtest
$ adb shell pm install -r "/data/local/tmp/com.mystudiotest.myapplicationtest"
    pkg: /data/local/tmp/com.mystudiotest.myapplicationtest
Success
//安装测试所在module的apk

$ adb push E:\workhome\libgdx\androidstudio\MyApplicationTest\apptest\build\outputs\apk\apptest-debug-androidTest-unaligned.apk /data/local/tmp/com.mystudiotest.myapplicationtest.test
$ adb shell pm install -r "/data/local/tmp/com.mystudiotest.myapplicationtest.test"
    pkg: /data/local/tmp/com.mystudiotest.myapplicationtest.test
Success
//安装测试apk

Running tests

$ adb shell am instrument -w -r   -e debug false -e class com.mystudiotest.myapplicationtest.AppInstrumentationTest com.mystudiotest.myapplicationtest.test/android.support.test.runner.AndroidJUnitRunner
Client not ready yet..Test running started

//运行Instrumentation测试

所以猜测是android studio自动安装apk导致待测apk被覆盖

但是即使我手动运行脚本,去掉上述第一步,又会出现classnotfound故障,找不到androidjunitrunner类

不管怎样,按照上述android studio脚本,android studio已经默认将espresso放在源代码module内部,按照github上googleandroid给出的例子,也是放在源代码module中的androidtest中,所以还是不纠结了

11、android studio2.1可以显示所有测试代码而不需要设置build variant,但是android studio需要在环境中设置ANDROID_HOME也就是SDK的位置


12、junit版本冲突:自动化测试需要Junit:4.8.2,而4.8.2版本没有org.junit.runners.model.Annitatable类,导致单元测试框架Robolectric缺少依赖,发出警告,需要在gradle配置单元测试依赖包:testCompile "junit:junit:4.12"


13、robolectric3.0有一处bug,单个单元测试运行是好的,但是多个单元测试一起运行却报错:

java.lang.ClassCastException: Cannot cast java.lang.Object to XXX

看源代码,是shadow对象互相干扰的问题,应该是robolectric的bug

将robolectric升级到3.1后,有一处改动:RobolectricGradleTestRunner的

public InstrumentationConfiguration createClassLoaderConfig()
 {}

改为:

public InstrumentationConfiguration createClassLoaderConfig(Config config)
 {}

也就是将测试用例的config传进来,可以看到框架做出了处理:

public Builder withConfig(Config config) {
      for (Class clazz : config.shadows()) {
        Implements annotation = clazz.getAnnotation(Implements.class);
        if (annotation == null) {
          throw new IllegalArgumentException(clazz + " is not annotated with @Implements");
        }

        String className = annotation.className();
        if (className.isEmpty()) {
          className = annotation.value().getName();
        }

        if (!className.isEmpty()) {
          addInstrumentedClass(className);
        }
      }
      for (String packageName : config.instrumentedPackages()) {
        addInstrumentedPackage(packageName);
      }
      return this;
    }

也就是只加载需要模拟的shadow类,原来的则是加载所有shadow类,打出log,发现原来的shadow类在两个测试用例中只进行一次初始化,而现在则要进行两次,原因是原来都当做shadow类来处理,而现在是只在config声明的shadow当做shadow处理,而没有声明的则当做原始类处理

运行后发现解决了这类故障

不过升级到3.1后,建议将java升级到java8,防止发送内存溢出

你可能感兴趣的:(android工具开发)