AndroidX.Test ActivityScenario: java.lang.AssertionError: Activity 永远不会成为请求状态 "[RESUMED]" (上一个生命周期转换



ActivityScenrio是Robolectric中ActivityController和ATSL中ActivityTestRule的替代品。

从ATSL重构到AndroidX测试时,我使用此代码在每次espresso测试之前启动IndexActivity。

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

然而,我的测试在80-90%的时间里都在拖延,并出现了这个错误。

java.lang.AssertionError:活动从未变为请求状态"[RESUMED]"(上一个生命周期转换="STOPPED"(

在尝试进行故障排除时,我将上面的内容更改为:

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

然而,我现在100%都会遇到同样的错误。

根据文件,我不确定为什么会发生这种情况。

我正在使用AndroidX Test Orchestrator,并在带有Api 28 的模拟器上进行测试

此处测试的完整堆栈跟踪:

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)

EDIT:现在在https://github.com/android/android-test/issues/143

声明:ActivitySvenue API的launch(Intent startActivityIntent)方法存在限制。它等待"活动"为Lifecycle.STATE.RESUMEDDESTROYED,如果不在4.5秒内,则抛出此错误。

上下文:我的应用程序使用IndexActivity加载一个配置,该配置指示应用程序进行某些API调用。然而,在它加载DialogActivity并且IndexActivity立即进入STOPPED之后。在接受DialogActivity中的条款后,IndexActivity返回到RESUMED,然后ActivityScenrio正常工作。在我的测试中,有一个竞赛条件,即Espresso是否可以在4.5秒内点击条款,将IndexActivity设置为RESUMED,或者在此之前是否会出现此错误。需要进行重大重构才能使用ActivityScenrio启动另一个"活动",所以这不是一个选项。

修复在活动场景的public static <A extends Activity> ActivityScenario<A> launch(Intent startActivityIntent)中,检查逻辑scenario.waitForActivityToBecomeAnyOf(State.RESUMED, State.DESTROYED);

如果您可以创建自己的自定义活动场景,并将这行代码调整为类似scenario.waitForActivityToBecomeAnyOf(State.STOPPED, State.DESTROYED);的代码,那么理论上它将适用于您。然后,您可以再次使用ActivityScenrio将"活动"移动到您想要的任何生命周期状态。

只使用旧的https://developer.android.com/reference/androidx/test/rule/ActivityTestRule直到谷歌在AndroidX测试中解决了这个问题。

TL;DR之所以发生这种情况,是因为"活动"的Lifecycle State不是ActivityScenario.Launch()等待的两种特定生命周期状态RESUMEDDESTROYED。您的活动可能处于创建API时未考虑的对话框或其他边缘场景的背景中。

对我来说,这是因为我在屏幕关闭的情况下插入了一个设备,并且运行了一个模拟器。我以为我要启动模拟器,但我在设备上运行它。由于屏幕关闭,测试始终无法转换到有效状态。

记录在案,这将在即将发布的版本中修复。https://github.com/android/android-test/issues/143

最新更新