Google Analytics - NullPointerException in Test

陌路散爱 提交于 2019-12-23 09:31:59

问题


I'm getting the following NPE in a Robolectric test on a Travis build-server, and I'm having trouble pinpointing why. I'm unable to reproduce this issue locally.

Anybody know what causes onServiceConnected to be called? That might help me pinpoint the issue. From what I can tell this is a Google Play Services - Google Analytics issue.

java.lang.NullPointerException
    at com.google.android.gms.analytics.c$a.onServiceConnected(Unknown Source)
    at com.google.android.gms.analytics.c$a.onServiceConnected(Unknown Source)
    at org.robolectric.shadows.ShadowApplication$2.run(ShadowApplication.java:257)
    at org.robolectric.util.Scheduler$PostedRunnable.run(Scheduler.java:162)
    at org.robolectric.util.Scheduler.runOneTask(Scheduler.java:107)
    at org.robolectric.util.Scheduler.advanceTo(Scheduler.java:92)
    at org.robolectric.util.Scheduler.advanceToLastPostedRunnable(Scheduler.java:68)
    at org.robolectric.util.Scheduler.unPause(Scheduler.java:25)
    at org.robolectric.shadows.ShadowLooper.unPause(ShadowLooper.java:228)
    at org.robolectric.shadows.ShadowLooper.runPaused(ShadowLooper.java:267)
    at org.robolectric.util.ActivityController.create(ActivityController.java:144)
    at org.robolectric.util.ActivityController.create(ActivityController.java:154)
    at com.company.search.activities.loginjoin.LoginActivityTest.setup(LoginActivityTest.java:20)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24)
    at org.robolectric.RobolectricTestRunner$2.evaluate(RobolectricTestRunner.java:250)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
    at org.robolectric.RobolectricTestRunner$1.evaluate(RobolectricTestRunner.java:177)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
    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:69)
    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:105)
    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:355)
    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)

To my knowledge, I'm not initializing GA anywhere for my unit tests. I have a general "fake" analytics tracker that gets used whenever tests are run. Just in case, I've added the following line in the constructor of my fake tracker which gets created in onCreate of the application:

GoogleAnalytics.getInstance(context).setAppOptOut(true);

In case this is of relevance, it's breaking on a box with Java 1.7.0_u55.

EDIT:

I saw the following in the logs of a failed test today. I'm not sure it was the cause of the crash though. Might give some insight.

E/GAV3: Thread[GAThread,5,main]: Error on GAThread: java.lang.NullPointerException
    at org.robolectric.shadows.ShadowLooper.getMainLooper(ShadowLooper.java:66)
    at android.os.Looper.getMainLooper(Looper.java)
    at android.database.sqlite.SQLiteDatabase.isMainThread(SQLiteDatabase.java:391)
    at android.database.sqlite.SQLiteDatabase.getThreadDefaultConnectionFlags(SQLiteDatabase.java:381)
    at android.database.sqlite.SQLiteProgram.__constructor__(SQLiteProgram.java:58)
    at android.database.sqlite.SQLiteProgram.<init>(SQLiteProgram.java:41)
    at android.database.sqlite.SQLiteStatement.<init>(SQLiteStatement.java:31)
    at android.database.sqlite.SQLiteDatabase.compileStatement(SQLiteDatabase.java:992)
    at android.database.DatabaseUtils.longForQuery(DatabaseUtils.java:799)
    at android.database.sqlite.SQLiteDatabase.getVersion(SQLiteDatabase.java:862)
    at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:242)
    at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:164)
    at com.google.android.gms.analytics.ac$a.getWritableDatabase(Unknown Source)
    at com.google.android.gms.analytics.ac$a.getWritableDatabase(Unknown Source)
    at com.google.android.gms.analytics.ac.G(Unknown Source)
    at com.google.android.gms.analytics.ac.G(Unknown Source)
    at com.google.android.gms.analytics.ac.i(Unknown Source)
    at com.google.android.gms.analytics.ac.i(Unknown Source)
    at com.google.android.gms.analytics.s.bk(Unknown Source)
    at com.google.android.gms.analytics.s.bk(Unknown Source)
    at com.google.android.gms.analytics.s.bJ(Unknown Source)
    at com.google.android.gms.analytics.s.bJ(Unknown Source)
    at com.google.android.gms.analytics.s.a(Unknown Source)
    at com.google.android.gms.analytics.s$2.run(Unknown Source)
    at com.google.android.gms.analytics.s$2.run(Unknown Source)
    at com.google.android.gms.analytics.t.run(Unknown Source)
    at com.google.android.gms.analytics.t.run(Unknown Source)

E/GAV3: Thread[GAThread,5,main]: Google Analytics is shutting down.

Looks like a problem with SQLite and GA?

Another Update:

For updates, see the linked github issue (https://github.com/robolectric/robolectric/issues/1075). I'm reverting back to v3 for the time being.


回答1:


The solution of Akeem works for me.

This is what I use for Robolectic 3.0, which has some changes:

import org.robolectric.RuntimeEnvironment;
import org.robolectric.Shadows;
import org.robolectric.shadows.ShadowApplication;

ShadowApplication shadowApplication = Shadows.shadowOf(RuntimeEnvironment.application);
shadowApplication.declareActionUnbindable("com.google.android.gms.analytics.service.START");



回答2:


The fix is to add the following lines in ALL of your test suites (because you don't know which test case would be run first)

ShadowApplication shadowApplication = Robolectric.shadowOf(Robolectric.application);
shadowApplication.declareActionUnbindable("com.google.android.gms.analytics.service.START");

Alternatively you can create a custom shadow class for your application that doesn't bind services:

import android.app.Application;
import android.content.Intent;
import android.content.ServiceConnection;
import android.util.Log;

import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
import org.robolectric.shadows.ShadowApplication;


@Implements(Application.class)
public class MyShadowApplication extends ShadowApplication {
    @Implementation
    public boolean bindService(Intent intent, final ServiceConnection serviceConnection, int i) {
        Log.d("Robolectric", intent.getAction());
        return false;
    }
}

And run all your test cases with the shadow class

@Config(emulateSdk = 18, shadows = {MyShadowApplication.class})



回答3:


This is what I figured out (and solved in my case) : Somewhere (probably when initializing Google Analytics), there is a call to start a service.

I thought that this call was to start one of my app's services, so I added

Robolectric.getShadowApplication().setComponentNameAndServiceForBindService(
            new ComponentName(Robolectric.application, MyService.class),
            new StalkerService() {
                @Override
                public Context getApplicationContext() {
                    return Robolectric.application;
                }
            }.onBind(null)
    );

in my TestApplication code, before calling super.onCreate. Gladly, it solved my problem - no more NPE, and all tests pass.

But, then I noticed that this is very weird solution, since I'm providing Robolectric the binder for my Service and not GA service... But it works, and I'm not sure why. So, I'm going to leave it here for you to test if it fixes your issues too.



来源:https://stackoverflow.com/questions/23528087/google-analytics-nullpointerexception-in-test

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!