6

我在 Travis 构建服务器上的 Robolectric 测试中得到以下 NPE,但我无法查明原因。我无法在本地重现此问题。

有人知道是什么原因导致 onServiceConnected 被调用吗?这可能有助于我查明问题。据我所知,这是一个 Google Play Services - Google Analytics 问题。

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)

据我所知,我不会在任何地方为我的单元测试初始化​​ GA。我有一个通用的“假”分析跟踪器,每当运行测试时都会使用它。以防万一,我在我的假跟踪器的构造函数中添加了以下行,它是在应用程序的 onCreate 中创建的:

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

如果这是相关的,它会在 Java 1.7.0_u55 的盒子上打破。

编辑:

我今天在失败的测试日志中看到了以下内容。我不确定这是坠机的原因。可能会提供一些见解。

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.

看起来像 SQLite 和 GA 的问题?

另一个更新:

有关更新,请参阅链接的 github 问题 ( https://github.com/robolectric/robolectric/issues/1075 )。我暂时恢复到 v3。

4

3 回答 3

4

Akeem 的解决方案对我有用。

这是我用于 Robolectic 3.0 的,它有一些变化:

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");
于 2015-02-26T09:22:46.660 回答
3

解决方法是在所有测试套件中添加以下行(因为您不知道首先运行哪个测试用例)

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

或者,您可以为您的应用程序创建一个不绑定服务的自定义影子类:

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;
    }
}

并使用影子类运行所有测试用例

@Config(emulateSdk = 18, shadows = {MyShadowApplication.class})
于 2014-11-03T21:02:03.063 回答
0

这就是我想出的(并在我的情况下解决了):某处(可能在初始化谷歌分析时),有一个启动服务的调用。

我认为这个调用是为了启动我的应用程序的一项服务,所以我添加了

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

在我的 TestApplication 代码中,在调用super.onCreate. 很高兴,它解决了我的问题——不再有 NPE,并且所有测试都通过了。

但是,后来我注意到这是一个非常奇怪的解决方案,因为我为我的服务而不是 GA 服务提供 Robolectric 活页夹......但它有效,我不知道为什么。所以,我将把它留在这里,让你测试它是否也能解决你的问题。

于 2014-11-03T17:11:35.583 回答