RobotiumTech / robotium

Android UI Testing
http://www.robotium.org
Apache License 2.0
2.86k stars 786 forks source link

ConcurrentModificationException when calling Solo.finishOpenedActivities #738

Closed renas closed 9 years ago

renas commented 9 years ago

From Jonathan...@gmail.com on February 19, 2015 06:21:27

This issue happens sporadically in various different projects I have created. The test projects follow the example as detailed in the example project. This is current being observed with version 5.2.1 of Robotium running on API 4.0 or higher. The stack trace is provided below:

I/TestRunner( 1244): ----- begin exception ----- I/TestRunner( 1244): I/TestRunner( 1244): java.util.ConcurrentModificationException I/TestRunner( 1244): at java.util.AbstractList$SimpleListIterator.next(AbstractList.java:62) I/TestRunner( 1244): at com.robotium.solo.ActivityUtils.getAllOpenedActivities(ActivityUtils.java:87) I/TestRunner( 1244): at com.robotium.solo.ActivityUtils.finishOpenedActivities(ActivityUtils.java:375) I/TestRunner( 1244): at com.robotium.solo.Solo.finishOpenedActivities(Solo.java:2582) I/TestRunner( 1244): at com.nessi.app.presentation.emails.EmailActivity_Test.tearDown(EmailActivity_Test.java:73) I/TestRunner( 1244): at junit.framework.TestCase.runBare(TestCase.java:140) I/TestRunner( 1244): at junit.framework.TestResult$1.protect(TestResult.java:115) I/TestRunner( 1244): at junit.framework.TestResult.runProtected(TestResult.java:133) I/TestRunner( 1244): at junit.framework.TestResult.run(TestResult.java:118) I/TestRunner( 1244): at junit.framework.TestCase.run(TestCase.java:124) I/TestRunner( 1244): at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:191) I/TestRunner( 1244): at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:176) I/TestRunner( 1244): at android.test.InstrumentationTestRunner.onStart(InstrumentationTestRunner.java:554) I/TestRunner( 1244): at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1701) I/TestRunner( 1244): ----- end exception -----

Original issue: http://code.google.com/p/robotium/issues/detail?id=659

renas commented 9 years ago

From renasr...@gmail.com on February 19, 2015 07:14:48

Thanks for reporting this. Are you running the test cases in different threads? Would it be possible for you to share your test project?

Owner: renasr...@gmail.com

renas commented 9 years ago

From Jonathan...@gmail.com on February 19, 2015 09:10:35

Here is a code sample of one place this has occurred, the code have been trimmed for brevity.

public class EmailActivity_Test extends ActivityInstrumentationTestCase2 {

private Solo solo;

@Inject
Api api;

public EmailActivity_Test() {
    super(EmailActivity.class);
}

@Override
protected void setUp() throws Exception {
    super.setUp();
    Injector.add(
            new AppModule(getInstrumentation().getTargetContext()),
            new FormatterModule(),
            new EmailTestModule());
    Injector.inject(this);

    User.setCurrentUser(TestData.buildUserTutor());
    Token.setCurrentToken(TestData.buildToken());
}

@Override
protected void tearDown() throws Exception {
    if (solo != null) {
        solo.finishOpenedActivities();
    }
    super.tearDown();
}

public void testClickingForwardGoesToCompose() throws Throwable {
    Email email = TestData.buildEmailTestData();
    List<EmailUser> emailUsers = TestData.buildEmailUserTestData();

    Intent intent = new Intent(Constants.ACTIONS.EMAIL);
    intent.putExtra(Constants.EXTRAS.EMAIL_ID, email.getId());
    setActivityIntent(intent);

    Mockito.doReturn(buildEmailResponse(email, emailUsers)).when(api).getEmail(Mockito.anyLong(), Mockito.eq(email.getId()));

    solo = new Solo(getInstrumentation(), getActivity());

    Instrumentation.ActivityMonitor monitor = getInstrumentation().addMonitor(new IntentFilter(Constants.ACTIONS.FORWARD_EMAIL), null, true);

    solo.clickOnMenuItem("Forward");

    Activity activity = monitor.waitForActivityWithTimeout(5000);
    assertTrue(activity instanceof ComposeEmailActivity);
}

}

renas commented 9 years ago

From renasr...@gmail.com on February 19, 2015 09:14:55

Interesting how you are using multiple frameworks in one test case. What happens if you remove:

Instrumentation.ActivityMonitor monitor = getInstrumentation().addMonitor(new IntentFilter(Constants.ACTIONS.FORWARD_EMAIL), null, true);

Activity activity = monitor.waitForActivityWithTimeout(5000); assertTrue(activity instanceof ComposeEmailActivity);

And instead use the Activity API:s in Robotium. E.g. solo.assertCurrentActivity(), solo.getCurrentActivity etc?

Also please use the latest Robotium version, 5.3.1.

renas commented 9 years ago

From Jonathan...@gmail.com on February 19, 2015 09:35:07

The problem with using assertCurrentActivity is the delay between clicking a view and when the next activity is actually on screen. I had it implemented the way you describe and would frequently see the test fail because the activity assert was triggering too fast. And using waitIdleSyncs or Thread.sleep as intermittently produces similar results. The only way to solve those issues has been to use an ActivityMonitor to wait for the activity to load. The thing though is that the test itself actually is succeeding its when trying to close the activities in the tearDown method that is having an issue.

renas commented 9 years ago

From renasr...@gmail.com on February 19, 2015 09:43:20

Thats strange. The activity assert should wait for the specified Activity for 10 seconds before failing.

Your'e getting the ConcurrentModificationException as solo.finishOpenedActivities() is triggered twice at the same time. The list holding the weak activity references can't handle that. You could do a log printout in tearDown() just to see which tests call the tearDown at the same time.

renas commented 9 years ago

From renasr...@gmail.com on February 19, 2015 09:47:21

It could also be that the teardown is run at the same time a new Activity is opened. You could end the test first when the new activity is opened. Basically use a solo.waitForActivity in the end.

renas commented 9 years ago

From Jonathan...@gmail.com on February 19, 2015 09:50:26

My apologies, I have not yet tried solo.assertCurrentActivty(). I wasn't aware that it would wait a few seconds for the specified activity. I am attempting to upgrade to version 5.3.1 and will swap in solo.assertCurrentActivty() and see if the failure pops up anymore today.

renas commented 9 years ago

From Jonathan...@gmail.com on February 20, 2015 08:56:36

Swapping out those ActivityMonitor for solo.assertCurrentActivty() seems to have done the trick. I did briefly try updating to 5.3.1 and had to roll back because it was causing others tests to start breaking that involved click things in a PopupWindow. Once I get a chance I will try upgrading again to see what the problem really is with that. Thanks for your assistance.

renas commented 9 years ago

From renasr...@gmail.com on February 25, 2015 09:25:08

Status: Invalid