Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AndroidX.Test ActivityScenario: java.lang.AssertionError: Activity never becomes requested state "[RESUMED]" (last lifecycle transition = "STOPPED")

ActivityScenario is a replacement of ActivityController in Robolectric and ActivityTestRule in ATSL.

When refactoring from ATSL to AndroidX Test, I am using this code to start my IndexActivity before each espresso test.

    @Before
public void launchActivity() {
    ActivityScenario<IndexActivity> scenario = ActivityScenario.launch(IndexActivity.class);
}

However, my tests are stalling out 80-90% of the time and throwing this error.

java.lang.AssertionError: Activity never becomes requested state "[RESUMED]" (last lifecycle transition = "STOPPED")

When trying to troubleshoot, I changed the above to:

@Before
public void launchActivity() {
    ActivityScenario<IndexActivity> scenario = ActivityScenario.launch(IndexActivity.class);
    scenario.moveToState(Lifecycle.State.RESUMED);
}

However, I am now getting the same error 100% of the time.

Following the documentation, I am not sure why this is happening.

I am using AndroidX Test Orchestrator and testing on an Emulator with Api 28

Full StackTrace for Test here:

10:54:42 V/InstrumentationResultParser: java.lang.AssertionError: Activity never becomes requested state "[RESUMED]" (last lifecycle transition = "STOPPED")
10:54:42 V/InstrumentationResultParser: at androidx.test.core.app.ActivityScenario.waitForActivityToBecomeAnyOf(ActivityScenario.java:228)
10:54:42 V/InstrumentationResultParser: at androidx.test.core.app.ActivityScenario.moveToState(ActivityScenario.java:368)
10:54:42 V/InstrumentationResultParser: at com.myapplication.android.test.HomeTest.launchActivity(HomeTest.java:30)
10:54:42 V/InstrumentationResultParser: at java.lang.reflect.Method.invoke(Native Method)
10:54:42 V/InstrumentationResultParser: at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
10:54:42 V/InstrumentationResultParser: at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
10:54:42 V/InstrumentationResultParser: at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
10:54:42 V/InstrumentationResultParser: at androidx.test.internal.runner.junit4.statement.RunBefores.evaluate(RunBefores.java:76)
10:54:42 V/InstrumentationResultParser: at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
10:54:42 V/InstrumentationResultParser: at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
10:54:42 V/InstrumentationResultParser: at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
10:54:42 V/InstrumentationResultParser: at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
10:54:42 V/InstrumentationResultParser: at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
10:54:42 V/InstrumentationResultParser: at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
10:54:42 V/InstrumentationResultParser: at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
10:54:42 V/InstrumentationResultParser: at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
10:54:42 V/InstrumentationResultParser: at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
10:54:42 V/InstrumentationResultParser: at androidx.test.ext.junit.runners.AndroidJUnit4.run(AndroidJUnit4.java:104)
10:54:42 V/InstrumentationResultParser: at org.junit.runners.Suite.runChild(Suite.java:128)
10:54:42 V/InstrumentationResultParser: at org.junit.runners.Suite.runChild(Suite.java:27)
10:54:42 V/InstrumentationResultParser: at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
10:54:42 V/InstrumentationResultParser: at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
10:54:42 V/InstrumentationResultParser: at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
10:54:42 V/InstrumentationResultParser: at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
10:54:42 V/InstrumentationResultParser: at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
10:54:42 V/InstrumentationResultParser: at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
10:54:42 V/InstrumentationResultParser: at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
10:54:42 V/InstrumentationResultParser: at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
10:54:42 V/InstrumentationResultParser: at androidx.test.internal.runner.TestExecutor.execute(TestExecutor.java:56)
10:54:42 V/InstrumentationResultParser: at androidx.test.runner.AndroidJUnitRunner.onStart(AndroidJUnitRunner.java:388)
10:54:42 V/InstrumentationResultParser: at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:2075)
like image 328
Mark Han Avatar asked Dec 03 '18 16:12

Mark Han


2 Answers

EDIT: This is now fixed in https://github.com/android/android-test/issues/143

Claim: There is a limitation within the launch(Intent startActivityIntent) method of the ActivityScenario API. It waits for the Activity to be Lifecycle.STATE.RESUMED or DESTROYED and if it isn't within 4.5 seconds then it throws this error.

Context: My application uses an IndexActivity to load a config which instructs the application on certain API calls to make. However, immediately after it loads a DialogActivity and the IndexActivity goes into STOPPED. On accepting terms within the DialogActivity the IndexActivity goes back into RESUMED and then ActivityScenario works properly. With my tests, there was a race condition on whether Espresso could click through the terms within 4.5 seconds to get the IndexActivity to be RESUMED or whether this error would throw before that. It would take major refactoring to enable another Activity to be launched with ActivityScenario so that was not an option.

The Fix Within public static <A extends Activity> ActivityScenario<A> launch(Intent startActivityIntent) of Activity Scenario, check the logic scenario.waitForActivityToBecomeAnyOf(State.RESUMED, State.DESTROYED);

If you can create your own custom Activity Scenario and adjust this line of code to be something like scenario.waitForActivityToBecomeAnyOf(State.STOPPED, State.DESTROYED); then it will theoretically work for you. You can then use ActivityScenario again to move the Activity into whatever Lifecycle State you want.

OR just use the old https://developer.android.com/reference/androidx/test/rule/ActivityTestRule until Google addresses this in AndroidX Test.

TL;DR This is happening because the Lifecycle.State of your Activity is not either of the two specific lifecycle states ActivityScenario.Launch() waits for, RESUMED or DESTROYED. Your activity is probably in the background of a dialog or another edge-case situation that was not thought about when creating the API.

like image 137
Mark Han Avatar answered Oct 05 '22 11:10

Mark Han


For the record, this will be fixed in upcoming release. https://github.com/android/android-test/issues/143

like image 25
Yuki Hamada Avatar answered Oct 05 '22 12:10

Yuki Hamada