Java.util.ConcurrentModificationException en las pruebas de JUnit

Esta es una especie de disparo en la oscuridad. Estoy recibiendo el error siguiente de vez en cuando al ejecutar mi unidad de prueba de unidad robolectric:

java.util.ConcurrentModificationException at java.util.LinkedList$ListItr.checkForComodification(LinkedList.java:966) at java.util.LinkedList$ListItr.next(LinkedList.java:888) at org.robolectric.shadows.ShadowResources.getOverlayedThemeValue(ShadowResources.java:294) at org.robolectric.shadows.ShadowResources.findAttributeValue(ShadowResources.java:284) at org.robolectric.shadows.ShadowResources.attrsToTypedArray(ShadowResources.java:187) at org.robolectric.shadows.ShadowResources.access$000(ShadowResources.java:51) at org.robolectric.shadows.ShadowResources$ShadowTheme.obtainStyledAttributes(ShadowResources.java:489) at android.content.res.Resources$Theme.obtainStyledAttributes(Resources.java) at android.content.Context.obtainStyledAttributes(Context.java:416) at android.view.View.__constructor__(View.java:3317) 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.internal.Shadow.invokeConstructor(Shadow.java:73) at org.robolectric.shadows.ShadowView.__constructor__(ShadowView.java:109) at android.view.View.<init>(View.java) at android.widget.TextView.<init>(TextView.java) at com.getbase.floatingactionbutton.FloatingActionsMenu.createLabels(FloatingActionsMenu.java:461) at com.getbase.floatingactionbutton.FloatingActionsMenu.onFinishInflate(FloatingActionsMenu.java:447) at android.view.LayoutInflater.rInflate(LayoutInflater.java:763) at android.view.LayoutInflater.rInflate(LayoutInflater.java:758) at android.view.LayoutInflater.rInflate(LayoutInflater.java:758) at android.view.LayoutInflater.inflate(LayoutInflater.java:492) at android.view.LayoutInflater.inflate(LayoutInflater.java:397) at android.view.LayoutInflater.inflate(LayoutInflater.java:353) at android.support.v7.app.ActionBarActivityDelegateBase.setContentView(ActionBarActivityDelegateBase.java:228) at android.support.v7.app.ActionBarActivity.setContentView(ActionBarActivity.java:102) at com.myapp.app.view.activity.MainActivityActivity.onCreate(MainActivityActivity.java:75) at android.app.Activity.performCreate(Activity.java:5133) 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.util.ActivityController$1.run(ActivityController.java:114) at org.robolectric.shadows.ShadowLooper.runPaused(ShadowLooper.java:309) at org.robolectric.shadows.CoreShadowsAdapter$2.runPaused(CoreShadowsAdapter.java:47) at org.robolectric.util.ActivityController.create(ActivityController.java:110) at com.myapp.app.BaseActivityRobolectricTest.startActivity(BaseActivityRobolectricTest.java:58) at com.myapp.app.BaseActivityRobolectricTest.startActivity(BaseActivityRobolectricTest.java:34) at com.myapp.app.view.activity.MainActivityActivityTest.setupActivity(MainActivityActivityTest.java:52) 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:234) 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:167) 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:48) 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:360) at org.gradle.internal.concurrent.DefaultExecutorFactory$StoppableExecutorImpl$1.run(DefaultExecutorFactory.java:64) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:745) 

Estoy teniendo un horrible tiempo haciendo luz de este stacktrace y lo que podría estar pasando. ¿Alguien se ha topado con esto y ha encontrado una solución?

Encontré un problema en el github de Robolectric que sugiere hacer un clean antes de ejecutar las pruebas. Aunque parece reducir al mínimo el número de veces que esta prueba falla, todavía falla ocasionalmente.

MainActivityActivity.java:75 es setContentView(R.layout.activity_main);

La prueba:

 @Before public void setupActivity() { setupAuthObjectGraphWithFakeData(); startActivity(RequestReviewsActivity.class, new ParentModule(), null); } protected void startActivity(Class<T> activityClass, Object module, Intent intent) { mActivityController = buildActivity(activityClass); if(intent != null) { mActivityController.withIntent(intent); } mActivity = mActivityController.get(); List<Object> modules = new ArrayList<>(); modules.addAll(mActivity.getModules()); modules.add(module); ObjectGraph objectGraph; if(mActivity instanceof AuthedActivity) { objectGraph = BaseApplication.getInstance().getAuthObjectGraph().plus(modules.toArray()); } else { objectGraph = BaseApplication.getInstance().getAppObjectGraph().plus(modules.toArray()); } mActivity.setObjectGraph(objectGraph); mActivityController.create(mBundle).start().resume(); } @Test public void testViewsAreAvailable() { assertThat(getActivity().mToolbar).isNotNull(); assertThat(getActivity().mContent).isNotNull(); assertThat(getActivity().mContentShadow).isNotNull(); assertThat(getActivity().mRequestRootFab).isNotNull(); assertThat(getActivity().mRequestReviewsList).isNotNull(); assertThat(getActivity().mRequestReviewsMainContent).isNotNull(); } 

Actualizar:

Este problema desaparece cuando no se realizan pruebas unitarias específicas de actividad (similares a las siguientes). Por el momento he tenido que comentar estas pruebas.

Estoy siguiendo generalmente el acercamiento de Robolectric encontrado aquí – http://blog.blundell-apps.com/android-gradle-app-with-robolectric-junit-tests/ con algunas actualizaciones (puesto que ese artículo es un pedacito viejo).

Estoy ejecutando las pruebas con una ./gradlew test

Si está usando algo como Fabric o Crashlytics, asegúrese de desactivarlo en sus pruebas Robolectric. Hemos estado funcionando en una edición muy similar y con una cierta depuración local, pudimos encontrar el hilo que causaba el problema. Cuando Fabric se inicializa, inicia un subproceso de fondo que accede a algunos recursos. Mi pensamiento es que esto es principalmente un error con Robolectric en que no maneja la carga de recursos en una manera segura de hilo, pero realmente no hay necesidad de Crashlytics en un entorno de prueba de unidad por lo que esta es una solución rápida.

Normalmente, un usuario inicializará Fabric o Crashlytics en su clase Application . Robolectric le permite hacer una clase de "Prueba" de la Application prefijando su clase actual con la palabra "Prueba". En su clase de Application original, haga un método separado para inicializar el sistema de informes de fallos. En su TestApplication , TestApplication ese método y asegúrese de que está vacío por lo que Fabric no se inicializa en las pruebas. Por ejemplo:

App.java

 public class App extends Application { @Override public void onCreate() { super.onCreate(); setupCrashReporting(); } protected void setupCrashReporting() { CrashlyticsCore core = new CrashlyticsCore.Builder() .disabled(BuildConfig.DEBUG) .build(); Crashlytics crashlytics = new Crashlytics.Builder() .core(core) .build(); Fabric.with(this, crashlytics); } } 

TestApp.java

 public class TestApp extends App { @Override protected void setupCrashReporting() { // Do nothing. } } 

Esto ayudó a resolver el problema en nuestras aplicaciones.

  • Ejecutar RoboElectric varias veces con diferentes sdk versión
  • ¿Cómo forzar un cambio de configuración en una prueba Android Robolectric?
  • Android + Robolectric - RuntimeException / InstantiationException en queryBuilder.query () en ContentProvider
  • Robolectric es-singlepane (/ solo-fragmento) -test
  • ¿Cómo encontrar recursos de la biblioteca de apoyo utilizando robolectric?
  • Cómo burlar los permisos para realizar pruebas en Android?
  • Robolectric Test no llama a textWatcher.onTextChanged
  • Robolectric lanza Recursos $ NotFoundException al intentar acceder al recurso en la carpeta raw
  • Robolectric personalizado TestRunner no funciona cuando se inicia desde Gradle
  • ¿Cómo puedo probar fragmentos con Robolectric?
  • Cómo simular un evento de arrastre en un ViewPager en Roboeléctrico?
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.