AndroidX.Test ActivityScenario: java.lang.AssertionError: Activity 永远不会变为请求状态“[RESUMED]”(最后一个生命周期转换

Posted

技术标签:

【中文标题】AndroidX.Test ActivityScenario: java.lang.AssertionError: Activity 永远不会变为请求状态“[RESUMED]”(最后一个生命周期转换 =“STOPPED”)【英文标题】:AndroidX.Test ActivityScenario: java.lang.AssertionError: Activity never becomes requested state "[RESUMED]" (last lifecycle transition = "STOPPED") 【发布时间】:2018-12-03 16:55:05 【问题描述】:

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

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

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

但是,我的测试在 80-90% 的情况下都会停止并抛出此错误。

java.lang.AssertionError: Activity 永远不会变为请求状态“[RESUMED]”(最后一个生命周期转换 =“STOPPED”)

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

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

但是,我现在 100% 的时间都遇到同样的错误。

按照文档,我不确定为什么会发生这种情况。

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

在这里进行测试的完整 StackTrace:

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)

【问题讨论】:

【参考方案1】:

编辑:这已在https://github.com/android/android-test/issues/143中得到修复

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

背景: 我的应用程序使用IndexActivity 来加载一个配置,该配置指示应用程序进行某些 API 调用。但是,在它加载DialogActivity 并且IndexActivity 立即进入STOPPED 之后。在接受DialogActivity 中的条款时,IndexActivity 会返回到RESUMED,然后 ActivityScenario 可以正常工作。在我的测试中,Espresso 是否可以在 4.5 秒内单击条款以使 IndexActivity 变为 RESUMED 或者是否会在此之前引发此错误,存在竞争条件。使用 ActivityScenario 启动另一个 Activity 需要进行重大重构,因此这不是一个选项。

修复 在Activity Scenario的public static &lt;A extends Activity&gt; ActivityScenario&lt;A&gt; launch(Intent startActivityIntent)内,检查逻辑scenario.waitForActivityToBecomeAnyOf(State.RESUMED, State.DESTROYED);

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

只需使用旧的https://developer.android.com/reference/androidx/test/rule/ActivityTestRule,直到 Google 在 AndroidX 测试中解决此问题。

TL;DR 发生这种情况是因为您的 Activity 的 Lifecycle.State 不是 ActivityScenario.Launch() 等待、RESUMEDDESTROYED 的两个特定生命周期状态之一。您的活动可能是在创建 API 时没有考虑到的对话或其他极端情况的背景中。

【讨论】:

嘿,马克!这可以被接受为答案吗?看起来更新的 androidx.test 解决了这个问题。【参考方案2】:

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

【讨论】:

【参考方案3】:

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

【讨论】:

以上是关于AndroidX.Test ActivityScenario: java.lang.AssertionError: Activity 永远不会变为请求状态“[RESUMED]”(最后一个生命周期转换 的主要内容,如果未能解决你的问题,请参考以下文章

AndroidX.Test ActivityScenario: java.lang.AssertionError: Activity 永远不会变为请求状态“[RESUMED]”(最后一个生命周期转换

uiautomator实现控件查找与点击

uiautomator实现控件查找与点击

运行测试用例文件时出现依赖错误

如何 UI 测试偏好片段

无法运行 Android Instrumented 测试