我在Android应用程序上的MainActivity检查用户是否已登录(存储在SharedPreferences中),以及是否未将用户带到LoginActivity。我正在尝试使用以下代码对此进行测试

public class MainActivityTest extends ActivityInstrumentationTestCase2<MainActivity> {

private static final int TIME_OUT = 5000; /* miliseconds */

private MainActivity mMainActivity;
private Instrumentation mInstrumentation;
private SharedPreferences mLoginPrefs;

public MainActivityTest() {
    super(MainActivity.class);
}

protected void setUp() throws Exception {
    super.setUp();

    setActivityInitialTouchMode(false);

    mMainActivity = getActivity();
    mInstrumentation = getInstrumentation();
    mLoginPrefs = mInstrumentation.getTargetContext().getSharedPreferences(LoginActivity.PREFS_NAME, Context.MODE_PRIVATE);

    SharedPreferences.Editor editor = mLoginPrefs.edit();
            // User is not logged in, so it should be redirect to LoginActivity
    editor.putBoolean("logged_in", false);
    editor.commit();
}

//...

public void testC_OpenLoginActivityIfUserIsNotLoggedIn() {
    ActivityMonitor monitor = mInstrumentation.addMonitor(LoginActivity.class.getName(), null, false);
    Activity nextActivity = mInstrumentation.waitForMonitorWithTimeout(monitor, TIME_OUT);

    assertNotNull(nextActivity);
    nextActivity.finish();

    SharedPreferences.Editor editor = mLoginPrefs.edit();
            // Login the user so we can continue the tests
    editor.putBoolean("logged_in", true);
    editor.commit();
}

但这不起作用,LoginActivity打开,但是waitForMonitorWithTimeout永不返回,因此我陷入了LoginActivity的困境(我需要回到MainActivity进行其他测试)。

类似于此SO Question的代码可用于按钮单击,但是任何单击都不会加载此活动,因此我认为监视器可能没有时间工作。

我只需要一种获取实际Activity的方法,就可以断言并使其完成以继续我的测试。

另一件事:如果可能的话,我希望不使用Robotium的方法。

最佳答案

为了解决您的问题,请首先查看两种最重要的测试方法:

Instrumentation#addMonitor(java.lang.String, android.app.Instrumentation.ActivityResult, boolean)
Instrumentation.ActivityMonitor#waitForActivity()

根据Android API参考:

addMonitor

添加一个新的Instrumentation.ActivityMonitor,只要启动活动,就会检查。监视器将在现有监视器之后添加;仅当现有监视器都无法自己处理Intent时,该监视器才会被命中。

waitForActivity

阻止,直到创建一个活动,该活动与此监视器的匹配并返回生成的活动。

现在让我们更清楚一点。

addMonitor 应该总是在
预期活动开始之前调用,永远​​不要太晚。

waitForActivity 应该仅在
预期活动开始之后调用,永远​​不要太早,因为它将阻止。

返回您的代码:

您将两者同时调用,而两者之间没有发生任何魔术。因此,对于addMonitor来说为时已晚,对于waitForActivity而言为时过早。
ActivityMonitor monitor = mInstrumentation.addMonitor(LoginActivity.class.getName(), null, false);
Activity nextActivity = mInstrumentation.waitForMonitorWithTimeout(monitor, TIME_OUT);

如果调用waitForActivity还为时过早,它将阻塞并失败,直到超时(因为尚未达到预期的活动),并且您将永远不会看到预期的活动正在启动。

如果调用addMonitor为时已晚,则监视将在启动预期活动之后开始,并且此后不再启动预期活动,因此waitForActivity将因为没有命中监视器而阻塞。

因此,无论预期活动是否开始
,两种情况之间的差异。对于您的情况,我认为调用addMonitor为时已晚。

解决方案非常简单:只需在您的LoginActivity启动之前将addMonitor移到足够早的位置,也许将其移至 setUp 方法即可,如下所示:
mInstrumentation = getInstrumentation();
ActivityMonitor monitor = mInstrumentation.addMonitor(LoginActivity.class.getName(), null, false);

顺便说一句,对于您的情况,有超时还是无超时都没有关系。

不要再删除不再需要的monitor,例如:
@Override
protected void tearDown() throws Exception {
    mInstrumentation.removeMonitor(monitor);
    super.tearDown();
}

07-27 17:09