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,防止發送內存溢出

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章