lihuazhang / robotium

Automatically exported from code.google.com/p/robotium
0 stars 0 forks source link

ConcurrentModificationException when calling Solo.finishOpenedActivities #659

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
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:55
4)
I/TestRunner( 1244):    at 
android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1701)
I/TestRunner( 1244): ----- end exception -----

Original issue reported on code.google.com by Jonathan...@gmail.com on 19 Feb 2015 at 2:21

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

Original comment by renasr...@gmail.com on 19 Feb 2015 at 3:14

GoogleCodeExporter commented 9 years ago
Here is a code sample of one place this has occurred, the code have been 
trimmed for brevity.

public class EmailActivity_Test extends 
ActivityInstrumentationTestCase2<EmailActivity> {

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

Original comment by Jonathan...@gmail.com on 19 Feb 2015 at 5:10

GoogleCodeExporter commented 9 years ago
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. 

Original comment by renasr...@gmail.com on 19 Feb 2015 at 5:14

GoogleCodeExporter commented 9 years ago
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.

Original comment by Jonathan...@gmail.com on 19 Feb 2015 at 5:35

GoogleCodeExporter commented 9 years ago
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.

Original comment by renasr...@gmail.com on 19 Feb 2015 at 5:43

GoogleCodeExporter commented 9 years ago
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.

Original comment by renasr...@gmail.com on 19 Feb 2015 at 5:47

GoogleCodeExporter commented 9 years ago
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.

Original comment by Jonathan...@gmail.com on 19 Feb 2015 at 5:50

GoogleCodeExporter commented 9 years ago
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.

Original comment by Jonathan...@gmail.com on 20 Feb 2015 at 4:56

GoogleCodeExporter commented 9 years ago

Original comment by renasr...@gmail.com on 25 Feb 2015 at 5:25