我在Travis构建服务器上的Robolectric测试中获得了以下NPE,但我无法确定原因。我无法在本地重现此问题。
有人知道是什么原因导致onServiceConnected被调用?这可能有助于我找出问题所在。据我所知,这是Google Play服务 - 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。
答案 0 :(得分: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");
答案 1 :(得分: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})
答案 2 :(得分:0)
这是我想出的(并在我的情况下解决): 在某个地方(可能在初始化Google Analytics时),有一个启动服务的电话。
我认为这个电话是为了启动我的某个应用服务,所以我添加了
Robolectric.getShadowApplication().setComponentNameAndServiceForBindService(
new ComponentName(Robolectric.application, MyService.class),
new StalkerService() {
@Override
public Context getApplicationContext() {
return Robolectric.application;
}
}.onBind(null)
);
在调用super.onCreate
之前,在我的TestApplication代码中。 很高兴,它解决了我的问题 - 不再是NPE,所有测试都通过了。
但是,我注意到这是一个非常奇怪的解决方案,因为我为Robolectric提供了我的服务的绑定器而不是GA服务......但是它有效,而我&#39 ;我不知道为什么。 所以,我将把它留在这里供你测试它是否也解决了你的问题。