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

Mar*_*Han 7 android android-testing android-espresso androidx

ActivityScenario 替代了 Robolectric 中的 ActivityController 和 ATSL 中的 ActivityTestRule。

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

    @Before
public void launchActivity() {
    ActivityScenario<IndexActivity> scenario = ActivityScenario.launch(IndexActivity.class);
}
Run Code Online (Sandbox Code Playgroud)

但是,我的测试有 80-90% 的时间会停止并抛出此错误。

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

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

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

但是,我现在 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)
Run Code Online (Sandbox Code Playgroud)

Mar*_*Han 5

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

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

上下文: 我的应用程序使用 anIndexActivity加载配置,该配置指示应用程序进行某些 API 调用。然而,紧随其后加载DialogActivityIndexActivity进入STOPPED。在内部的受理条件DialogActivityIndexActivity可以追溯到到RESUMED,然后ActivityScenario正常工作。随着我的测试中,没有关于咖啡是否可以通过4.5秒内的条款,请点击来获取竞争条件IndexActivityRESUMED还是这个错误会前抛出。需要进行重大重构才能使用 ActivityScenario 启动另一个 Activity,因此这不是一个选项。

public static <A extends Activity> ActivityScenario<A> launch(Intent startActivityIntent)Activity Scenario的Fix Within ,检查逻辑scenario.waitForActivityToBecomeAnyOf(State.RESUMED, State.DESTROYED);

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

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

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