![](/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.