![](/img/trans.png)
[英]Test recreating Android Activity using instrumentation and JUnit4
[英]Get current Activity on Android Instrumentation Test
我的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问题的代码适用于按钮点击,但任何点击都不会加载此活动,所以我想也许没有时间让显示器工作。
我只需要一种方法来获取实际的Activity,这样我就可以创建一个断言并完成继续我的测试。
另外一件事:如果可能的话,我更喜欢不使用Robotium的方法。
为了解决您的问题,首先看看您测试的两个最重要的方法:
Instrumentation#addMonitor(java.lang.String, android.app.Instrumentation.ActivityResult, boolean)
Instrumentation.ActivityMonitor#waitForActivity()
根据Android API参考:
添加一个新的Instrumentation.ActivityMonitor, 每当活动开始时都会检查它 。 监视器在任何现有监视器之后添加; 只有当现有监视器都不能自己处理Intent时,监视器才会被命中。
阻止,直到创建与此监视器匹配的活动,并返回生成的活动。
现在让我们说清楚一点吧。
应该在预期的活动开始之前调用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);
BTW,对于你的情况,超时或没有超时无关紧要。
不要忘记在不再需要后移除monitor
,例如:
@Override
protected void tearDown() throws Exception {
mInstrumentation.removeMonitor(monitor);
super.tearDown();
}
public static Activity getCurrentActivity() {
final Activity[] currentActivity = {null};
getInstrumentation().runOnMainSync(new Runnable() {
public void run() {
Collection resumedActivities = ActivityLifecycleMonitorRegistry.getInstance()
.getActivitiesInStage(RESUMED);
if (resumedActivities.iterator().hasNext()) {
currentActivity[0] = (Activity) resumedActivities.iterator().next();
}
}
});
return currentActivity[0];
}
你走在正确的轨道上。 您需要调用的方法是:
monitor.waitForActivityWithTimeout(TIME_OUT);
代替
mInstrumentation.waitForMonitorWithTimeout(monitor, TIME_OUT);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.