【问题标题】:Can't launch activity only once - Did you forget to launch the activity by calling getActivity() or startActivitySync or similar?只能启动一次活动 - 您是否忘记通过调用 getActivity() 或 startActivitySync 或类似方法启动活动?
【发布时间】:2019-06-10 09:01:37
【问题描述】:

我需要在所有测试之前只启动一次活动。 所以我为此使用注释@BeforeClass

这里是 Espresso 的测试:

@RunWith(AndroidJUnit4::class)
class JsonViewActivityTest {

    companion object {
        init {
            // things that may need to be setup before companion class member variables are instantiated
        }

        @get:Rule
var jsonViewIntentsTestRule = IntentsTestRule(JsonViewActivity::class.java, false, false)

        private val instrumentation = InstrumentationRegistry.getInstrumentation()
        private val context = instrumentation.getContext()
        private val targetContext = instrumentation.getTargetContext()
        private val intent = Intent(targetContext, JsonViewActivity::class.java)

        @BeforeClass
        @JvmStatic
        fun beforAll() {
            Intent(targetContext, JsonViewActivity::class.java)
            val bundle = Bundle()
            val inputStream = context.assets.open(StubUtil.TradersStub.ONE_TRADER_HAS_WALLETS.stubName)
            val content = inputStream.readBytes().toString(StandardCharsets.UTF_8)
            val jsonArray = GsonUtil.gson.fromJson(content, JsonArray::class.java)
            val jsonTrader = jsonArray.get(0)
            val trader = GsonUtil.gson.fromJson(jsonTrader, Trader::class.java)
            val wallet = trader.wallets[0]
            bundle.putString(JsonViewActivity.WALLET_JSON, GsonUtil.gson.toJson(wallet))
            intent.putExtras(bundle)

            jsonViewIntentsTestRule.launchActivity(intent)
        }

        @AfterClass
        @JvmStatic
        fun afterAll() {
            jsonViewIntentsTestRule.finishActivity()
        }
    }

    @Test
    fun toolBar_height() {
        onView(withId(R.id.toolBar))
                .check(ViewAssertions.matches(CustomMatchers.withHeightResId(R.dimen.tool_bar_height)))
    }
}

但测试 toolBar_height 失败并显示消息:

Client not ready yet..
Started running tests

java.lang.RuntimeException: No activities found. Did you forget to launch the activity by calling getActivity() or startActivitySync or similar?
at androidx.test.espresso.base.RootViewPicker.waitForAtLeastOneActivityToBeResumed(RootViewPicker.java:169)
at androidx.test.espresso.base.RootViewPicker.get(RootViewPicker.java:83)
at androidx.test.espresso.ViewInteractionModule.provideRootView(ViewInteractionModule.java:77)
at androidx.test.espresso.ViewInteractionModule_ProvideRootViewFactory.provideRootView(ViewInteractionModule_ProvideRootViewFactory.java:35)
at androidx.test.espresso.ViewInteractionModule_ProvideRootViewFactory.get(ViewInteractionModule_ProvideRootViewFactory.java:24)
at androidx.test.espresso.ViewInteractionModule_ProvideRootViewFactory.get(ViewInteractionModule_ProvideRootViewFactory.java:10)
at androidx.test.espresso.base.ViewFinderImpl.getView(ViewFinderImpl.java:62)
at androidx.test.espresso.ViewInteraction$2.call(ViewInteraction.java:276)
at androidx.test.espresso.ViewInteraction$2.call(ViewInteraction.java:268)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)

【问题讨论】:

  • beforAll 拼错了吗?
  • 我看到的正是你所看到的。我可以在运行任何测试之前启动一个活动,但是当第一个测试运行时,那个启动的活动就关闭了;我还可以看到活动视图窗口消失了。不涉及活动的测试可以正常工作,但发展活动的测试会失败。我能够针对同一个活动运行多个测试的唯一方法是添加 @Before 并为每个测试启动活动。当测试完成时,活动消失,我们再次启动它以进行下一次测试。这当然是我们试图避免的。

标签: android-espresso


【解决方案1】:

我跟踪了 AndroidJUnit4 代码,直到发现发生了什么。快速回答是,所有打开的 Activity 在每次测试开始之前都会自动“完成”。这是在 android.support.test.runner.MonitoringInstrumentation 中完成的。该类包含一个实现 Runnable 的公共内部类 ActivityFinisher。该类的 run 方法在每个测试开始之前被调用。以下是该代码的作用:

public void run() {
  List<Activity> activities = new ArrayList<>();

  for (Stage s : EnumSet.range(Stage.CREATED, Stage.STOPPED)) {
    activities.addAll(mLifecycleMonitor.getActivitiesInStage(s));
  }

  Log.i(TAG, "Activities that are still in CREATED to STOPPED: " + activities.size());

  for (Activity activity : activities) {
    if (!activity.isFinishing()) {
      try {
        Log.i(TAG, "Finishing activity: " + activity);
        activity.finish();
      } catch (RuntimeException e) {
        Log.e(TAG, "Failed to finish activity.", e);
      }
    }
  }
}

对 activity.finish() 的调用是导致您收到“未找到活动”消息的罪魁祸首。简而言之,AndroidJUnit4 没有被实现来做你想做的事情。我能理解你为什么要这样做,但是现成的 AndroidJUnit4Runner 不能那样工作。

我没有调查是否有解决此问题的简单方法。您可以做的一件简单的事情是构建您的测试类以仅包含一个测试。在 @Before 方法中启动您想要的活动,并在该单个 @Test 方法中执行所有活动测试。这可以防止活动在每次测试中再次“完成”和“开始”。解决此问题的另一种可能方法是编写您自己的自定义运行器类,这可能比您想要做的工作多一点。不幸的是,我不知道这种方法是否真的有效。或者您是否还会遇到同样的问题。

我的回答保持原样,向其他人提出一个悬而未决的问题,即是否有一种简单的方法可以在多个测试中保持 android 活动处于打开状态。

【讨论】:

  • annotation "@Before" 表示每次开始前每次测试都会用 "@Before" 开始方法注解。我不需要这个。
  • 如果你在@BeforeClass 或测试类的默认构造函数中这样做,你会遇到同样的问题,我试过了。每次测试后都会调用 ActivityFinisher,如果我在执行第一次测试之前没有记错的话。您只是无法启动在多个测试范围内保持活跃的活动。
猜你喜欢
  • 2019-08-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多