2015-02-11 13 views
10

Dieser ist eine Art von Schuss in der Dunkelheit. Ich erhalte gelegentlich die folgende Fehlermeldung, wenn meine robolectric Unit-Test-Suite ausgeführt wird:java.util.ConcurrentModificationException in JUnit Tests

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) 

Ich bin eine schreckliche Zeit macht Licht dieser stacktrace hat und was gehen könnte. Ist jemand darauf gestoßen und hat eine Lösung gefunden?

Ich habe ein Problem bei Robolectric's GitHub gefunden, das vor der Ausführung der Tests eine clean macht. Während es scheint, die Anzahl der Male zu minimieren, die dieser Test fehlschlägt, scheitert es gelegentlich.

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

Der Test:

@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(); 
} 

Update:

Dieses Problem geht weg, wenn nicht Aktivität bestimmte Unit-Tests (ähnlich dem folgenden) läuft . Vorläufig musste ich diese Tests auskommentieren.

Ich folge im Allgemeinen dem Robolectric Ansatz hier - http://blog.blundell-apps.com/android-gradle-app-with-robolectric-junit-tests/ mit einigen Updates (da dieser Artikel ein bisschen alt ist).

ich die Tests mit einem ./gradlew test

+1

Wo ist Ihr Code? –

+0

meine Frage aktualisiert, @KickButtowski – loeschg

+0

Das ist sehr faszinierend :) Wie laufen Sie Tests? Ist es Zufall? –

Antwort

10

Ausführung Wenn Sie so etwas wie Stoff oder Crashlytics verwenden, stellen Sie sicher, dass es in Ihrem Robolectric Test zu deaktivieren. Wir haben in einem sehr ähnlichen Problem ausgeführt und durch einige lokale Debugging konnten wir den Thread finden, der das Problem verursacht hat. Wenn Fabric initialisiert wird, wird ein Hintergrundthread gestartet, der auf einige Ressourcen zugreift. Mein Gedanke ist, dass dies in erster Linie ein Fehler bei Robolectric ist, da das Laden von Ressourcen nicht Thread-sicher gehandhabt wird, aber Crashlytics in einer Testumgebung für Einheiten nicht benötigt wird, daher ist dies eine schnelle Lösung.

Normalerweise initialisiert ein Benutzer Fabric oder Crashlytics in ihrer Application Klasse. Robolectric ermöglicht es Ihnen, eine "Test" Application Klasse zu machen, indem Sie Ihrer aktuellen Klasse das Wort "Test" voranstellen. Führen Sie in Ihrer ursprünglichen Klasse Application eine separate Methode zum Initialisieren des Absturzmeldungssystems aus. Überschreiben Sie diese Methode in Ihrer TestApplication und stellen Sie sicher, dass sie leer ist, damit Fabric in Ihren Tests nicht initialisiert wird. Zum Beispiel:

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

Dies trug dazu bei, das Problem in unsere Apps zu lösen.

+2

Glad haben * unser * Problem :) – loeschg

+0

Vielen Dank für die gemeinsame Nutzung der Lösung gelöst, aber meine Sorge ist Crashlytics nicht in der Lage ist auf diese Weise Abstürze im Debug-Modus zu fangen, wenn man mit vielen Testern in einer großen Organisation ist, dass Verwenden Sie Debug-Version, dann sind Sie in Problem anders (wenn sie Release-Version zum Testen verwenden) dann ist dies eine geniale Idee. – Hesam

+1

@Hesam wenn Sie es wollen im Debug arbeiten baut, dann entfernen Sie einfach das '.disabled (BuildConfig.DEBUG)' Linie und dann wird es aktiviert sein, für alle Versionen (außer Test so lange baut, wie Sie die 'TestApp' Klasse present) – plackemacher

Verwandte Themen