简体   繁体   中英

Asynchronous test code in Robolectric 3 with Play Services

I'm using Robolectric 3 rc2 with OkHttp Mock WebServer and Google Play Services.

I need to test the parsing of a json and related processing associated to it using the mock server and the server client have already using. The whole server client call is running in background with okhttp asynchronous call. The whole project if a library project.

Full code here

Gradle config :

testCompile 'org.apache.maven:maven-ant-tasks:2.1.3'
testCompile ("org.robolectric:robolectric:3.0-rc2"){
    exclude module: 'commons-logging'
    exclude module: 'httpclient'
}
testCompile 'com.google.android.gms:play-services:7.0.0'
testCompile ("org.robolectric:shadows-play-services:3.0-rc2"){
    exclude module: 'commons-logging'
    exclude module: 'httpclient'
}
testCompile 'org.robolectric:shadows-support-v4:3.0-rc2'
testCompile 'org.assertj:assertj-core:1.7.0'
testCompile 'com.squareup.okhttp:mockwebserver:1.2.1'

I'm running the test why command line :

./gradlew mymodule:clean mymodule:assembleDebug mymodule:testDebug --info

Error

I've got an error related to google play services java.lang.IllegalStateException: Calling this from your main thread can lead to deadlock

I'm surely doing something wrong when gettign AdvertisingId...

Complete stacktrace :

java.lang.RuntimeException: java.lang.IllegalStateException: Calling this from your main thread can lead to deadlock
    at org.robolectric.util.SimpleFuture.run(SimpleFuture.java:57)
    at org.robolectric.shadows.ShadowAsyncTask$2.run(ShadowAsyncTask.java:93)
    at org.robolectric.util.Scheduler.runOrQueueRunnable(Scheduler.java:218)
    at org.robolectric.util.Scheduler.postDelayed(Scheduler.java:73)
    at org.robolectric.util.Scheduler.post(Scheduler.java:60)
    at org.robolectric.shadows.ShadowAsyncTask.execute(ShadowAsyncTask.java:90)
    at android.os.AsyncTask.execute(AsyncTask.java)
    at com.example.sdk.adServer.ServerClient.<init>(ServerClient.java:101)
    at com.example.sdk.ServerClientTest.testLongTask(ServerClientTest.java:123)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
    at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31)
    at org.robolectric.RobolectricTestRunner$2.evaluate(RobolectricTestRunner.java:235)
    at org.junit.runners.BlockJUnit4ClassRunner.runNotIgnored(BlockJUnit4ClassRunner.java:79)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:71)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:49)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
    at org.robolectric.RobolectricTestRunner$1.evaluate(RobolectricTestRunner.java:168)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
    at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.runTestClass(JUnitTestClassExecuter.java:86)
    at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.execute(JUnitTestClassExecuter.java:49)
    at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassProcessor.processTestClass(JUnitTestClassProcessor.java:64)
    at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:50)
    at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
    at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
    at org.gradle.messaging.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:32)
    at org.gradle.messaging.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:93)
    at com.sun.proxy.$Proxy2.processTestClass(Unknown Source)
    at org.gradle.api.internal.tasks.testing.worker.TestWorker.processTestClass(TestWorker.java:106)
    at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
    at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
    at org.gradle.messaging.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:360)
    at org.gradle.internal.concurrent.DefaultExecutorFactory$StoppableExecutorImpl$1.run(DefaultExecutorFactory.java:64)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.IllegalStateException: Calling this from your main thread can lead to deadlock
    at com.google.android.gms.common.internal.zzx.zzbe(Unknown Source)
    at com.google.android.gms.common.internal.zzx.zzbe(Unknown Source)
    at com.google.android.gms.ads.identifier.AdvertisingIdClient.finish(Unknown Source)
    at com.google.android.gms.ads.identifier.AdvertisingIdClient.finish(Unknown Source)
    at com.google.android.gms.ads.identifier.AdvertisingIdClient.getAdvertisingIdInfo(Unknown Source)
    at com.google.android.gms.ads.identifier.AdvertisingIdClient.getAdvertisingIdInfo(Unknown Source)
    at com.example.sdk.adServer.ServerClient$RetrieveAdvertisingId.doInBackground(ServerClient.java:459)
    at com.example.sdk.adServer.ServerClient$RetrieveAdvertisingId.doInBackground(ServerClient.java:452)
    at org.robolectric.util.ReflectionHelpers$3.run(ReflectionHelpers.java:144)
    at org.robolectric.util.ReflectionHelpers.traverseClassHierarchy(ReflectionHelpers.java:241)
    at org.robolectric.util.ReflectionHelpers.callInstanceMethod(ReflectionHelpers.java:138)
    at org.robolectric.shadows.ShadowAsyncTaskBridge.doInBackground(ShadowAsyncTaskBridge.java:20)
    at org.robolectric.shadows.ShadowAsyncTask$BackgroundWorker.call(ShadowAsyncTask.java:147)
    at org.robolectric.util.SimpleFuture.run(SimpleFuture.java:52)
java.lang.RuntimeException: java.lang.IllegalStateException: Calling this from your main thread can lead to deadlock

The message from the exception explicitly describes what you are doing wrong. Apparently you should not call AdvertisingIdClient on UI thread because the library doesn't allow it (the reason is stated above. It could lead to deadlock).

Therefore, you have to use AsyncTask or any other background task libraries in order to call this API.

AsyncTask<Void, Void, String> task = new AsyncTask<Void, Void, String>() {
        @Override
        protected String doInBackground(Void... params) {
            AdvertisingIdClient.Info idInfo;
            String advertId = null;
            try {
                idInfo = AdvertisingIdClient.getAdvertisingIdInfo(context);
                advertId = idInfo.getId();
            } catch (GooglePlayServicesNotAvailableException|GooglePlayServicesRepairableException|IOException e) {
                e.printStackTrace();
            }
            return advertId;
        }

        @Override
        protected void onPostExecute(final String advertId) {
            KakaoTaskQueue.getInstance().addTask(new KakaoResultTask<EventsLogResponse>(callback) {
                @Override
                public EventsLogResponse call() throws Exception {
                    if (advertId == null)
                        throw new IllegalAccessException("Could not get adid from the device.");
                    rootEvent.setFrom(advertId);
                    return EventsApi.requestLoggingEvents(rootEvent, leafEvents);
                }
            });
        }
    };
    task.execute();

This is how you call getAdvertisingIdInfo method in AdvertisingIdClient class using AsyncTask . Comment if you have any other question :)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM