【问题标题】:How to test startActivity() call in onCreate()?如何在 onCreate() 中测试 startActivity() 调用?
【发布时间】:2017-02-08 02:12:36
【问题描述】:

我有一个包含以下代码的活动:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    if (mUser.getLoggedInUser() != null) {
        startActivity(new Intent(this, MainActivity.class));
        finish();
        return;
    }
}

因此,如果用户已登录,它应该启动 MainActivity 并立即完成。我想编写一个单元测试来验证 MainActivity 是否实际启动。我尝试了以下方法,使用 Espresso 和 IntentsTestRule:

@Test
public void testUserLoggedIn() {
    Intents.init();
    mUser = new User();
    mActivityRule.launchActivity(null);
    intended(hasComponent(MainActivity.class.getName()), times(1));
    Intents.release();
}

mUser 是通过依赖注入设置的,并且活动按预期运行。但是,测试失败并显示以下输出:

java.lang.RuntimeException: Could not launch intent Intent { act=android.intent.action.MAIN flg=0x14000000 cmp=global.snappy.android/.activities.onboarding.FirstStartActivity } within 45 seconds. Perhaps the main thread has not gone idle within a reasonable amount of time? There could be an animation or something constantly repainting the screen. Or the activity is doing network calls on creation? See the threaddump logs. For your reference the last time the event queue was idle before your activity launch request was 1486519735157 and now the last time the queue went idle was: 1486519735163. If these numbers are the same your activity might be hogging the event queue.
at android.support.test.runner.MonitoringInstrumentation.startActivitySync(MonitoringInstrumentation.java:360)
at android.support.test.rule.ActivityTestRule.launchActivity(ActivityTestRule.java:219)
at global.snappy.android.activities.onboarding.FirstStartActivityTest.testUserLoggedIn(FirstStartActivityTest.java:108)
at java.lang.reflect.Method.invoke(Native Method)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at android.support.test.internal.statement.UiThreadStatement.evaluate(UiThreadStatement.java:55)
at android.support.test.rule.ActivityTestRule$ActivityStatement.evaluate(ActivityTestRule.java:270)
at org.junit.rules.RunRules.evaluate(RunRules.java:20)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runners.Suite.runChild(Suite.java:128)
at org.junit.runners.Suite.runChild(Suite.java:27)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
at android.support.test.internal.runner.TestExecutor.execute(TestExecutor.java:59)
at android.support.test.runner.AndroidJUnitRunner.onStart(AndroidJUnitRunner.java:262)
at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1886)

在 Espresso 有时间附加测试之前,该活动似乎已关闭。删除 onCreate() 中的 finish() 调用不会改变这一点。有没有办法测试这种行为? Espresso 会更好,但如果需要,我也可以使用其他框架。

【问题讨论】:

  • 您确定您没有使用mActivityRule.launchActivity(null) 两次启动相同的活动吗?您的规则是否将 false 作为第三个构造函数参数?
  • 是,launchActivity参数设置为false:new IntentsTestRule<>(FirstStartActivity.class, true, false)

标签: android unit-testing junit android-espresso


【解决方案1】:

您可以为您的活动创建一个Spy 类。 然后,您可以检查是否使用MainActivity 作为参数调用了startActivity

测试框架很好,但有时纯代码看起来更好,而且更灵活。

您的 Spy 类看起来像这样(假设您的 Activity 名称是 MyActivity)。

public class MyActivitySpy extends MyActivity {
  private boolean startActivityWasCalledToStartMainActivity;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
  }

  @Override
  public startActivity(Intent intent) {
   if(intentWithActivityName(intent, MainActivity.class.getSimpleName())) {
       startActivityWasCalledToStartMainActivity ;
    }
  }

  private boolean intentWithActivityName(Intent intent, String activityName) {
      activityName.equals(intent.getComponent().getClassName());
  }

  public boolean wasStartActivityCalledToStartMainActivity() {
      return startActivityWasCalledToStartMainActivity;
  }
}

那么,你的测试会是这样的。

@Test
public void testUserLoggedIn() {
    //launch MyActivitySpy instead of your real MyActivity
    assertTrue(myActivitySpy.wasStartActivityCalledToStartMainActivity());
}

【讨论】:

  • 这听起来是个好主意。不幸的是,它失败了,因为 Android 找不到 Activity。将活动添加到androidTest/AndroidManifest.xml 后,仍然无法解析活动。你有什么解决办法吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-27
相关资源
最近更新 更多