Issue
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)
Solution
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.
Answered By - Mark Han
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.