2012-04-27 24 views
7

如何創建測試活動內生成的Intent內容的Android JUnit測試用例?我該如何單元測試從活動啓動/發送的Intent?

我有一個包含EditText窗口的Activity,當用戶輸入完所需數據後,Activity將Intent發送到IntentService,IntentService記錄數據並繼續執行應用程序進程。下面是我要測試的類中,OnEditorActionListener/PasscodeEditorListener被創建爲一個單獨的類:

public class PasscodeActivity extends BaseActivity { 
    EditText     m_textEntry = null; 
    PasscodeEditorListener  m_passcodeEditorListener = null; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.passcode_activity); 

     m_passcodeEditorListener = new PasscodeEditorListener(); 
     m_textEntry = (EditText) findViewById(R.id.passcode_activity_edit_text); 
     m_textEntry.setTag(this); 
     m_textEntry.setOnEditorActionListener(m_passcodeEditorListener); 
    } 

    @Override 
    protected void onPause() { 
     super.onPause(); 
     /* 
     * If we're covered for any reason during the passcode entry, 
     * exit the activity AND the application... 
     */ 
     Intent finishApp = new Intent(this, CoreService.class); 
     finishApp.setAction(AppConstants.INTENT_ACTION_ACTIVITY_REQUESTS_SERVICE_STOP); 
     startService(finishApp); 
     finish(); 
    } 

} 



class PasscodeEditorListener implements OnEditorActionListener{ 
    @Override 
    public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { 
     PasscodeActivity activity = (PasscodeActivity) v.getTag(); 
     boolean imeSaysGo = ((actionId & EditorInfo.IME_ACTION_DONE)!=0)?true:false; 
     boolean keycodeSaysGo = ((null != event) && 
       (KeyEvent.ACTION_DOWN == event.getAction()) && 
       (event.getKeyCode() == KeyEvent.KEYCODE_ENTER))?true:false; 

     if (imeSaysGo || keycodeSaysGo){ 
      CharSequence seq = v.getText(); 
      Intent guidEntry = new Intent(activity, CoreService.class); 
      guidEntry.setAction(AppConstants.INTENT_ACTION_PASSCODE_INPUT); 
      guidEntry.putExtra(AppConstants.EXTRA_KEY_GUID, seq.toString()); 
      activity.startService(guidEntry); 
      return true; 
     } 
     return false; 
    } 
} 

我怎樣才能攔截活動產生的兩種可能的對外意圖和驗證其內容是什麼?

感謝

+0

你在使用模擬器嗎?也許我錯過了一些東西,但是難道你不能這樣測試它嗎? – Nick 2012-04-27 00:40:06

+0

我一直在使用模擬器和手機,但我不認爲應該有所不同。我已經看到了很多方法來將Intents注入任何特定的被測活動,但沒有很多方法來觀察輸出。看到另一篇帖子,他們設置了ContextWrapper並攔截了對「startService()」的調用。這適用於第一次通話,但不適用於後續通話。一項活動可以在不關閉的情況下發布多個意圖,我對觀看/測試所有內容感興趣。 – 2012-04-27 03:38:12

回答

6

我想通了如何使用ContextWrapper與其他網站的幫助。

使用ContextWrapper並覆蓋所有意圖函數。對所有我的Activity測試進行概括,我擴展了ActivityUnitTestCase類並將解決方案實現爲一個墊片。享受:

import android.app.Activity; 
import android.app.Instrumentation; 
import android.content.ComponentName; 
import android.content.Context; 
import android.content.ContextWrapper; 
import android.content.Intent; 
import android.test.ActivityUnitTestCase; 

public class IntentCatchingActivityUnitTestCase<T extends Activity> extends ActivityUnitTestCase<T> { 

    protected Activity m_activity; 
    protected Instrumentation m_inst; 
    protected Intent[] m_caughtIntents; 
    protected IntentCatchingContext m_contextWrapper; 

    protected class IntentCatchingContext extends ContextWrapper { 
     public IntentCatchingContext(Context base) { 
      super(base); 
     } 

     @Override 
     public ComponentName startService(Intent service) { 
      m_caughtIntents = new Intent[] { service }; 
      return service.getComponent(); 
     } 

     @Override 
     public void startActivities(Intent[] intents) { 
      m_caughtIntents = intents; 
      super.startActivities(intents); 
     } 

     @Override 
     public void startActivity(Intent intent) { 
      m_caughtIntents = new Intent[] { intent }; 
      super.startActivity(intent); 
     } 

     @Override 
     public boolean stopService(Intent intent) { 
      m_caughtIntents = new Intent[] { intent }; 
      return super.stopService(intent); 
     } 
    } 

    // --// 
    public IntentCatchingActivityUnitTestCase(Class<T> activityClass) { 
     super(activityClass); 
    } 

    protected void setUp() throws Exception { 
     super.setUp(); 
     m_contextWrapper = new IntentCatchingContext(getInstrumentation().getTargetContext()); 
     setActivityContext(m_contextWrapper); 
     startActivity(new Intent(), null, null); 
     m_inst = getInstrumentation(); 
     m_activity = getActivity(); 
    } 

    protected void tearDown() throws Exception { 
     super.tearDown(); 
    } 

} 
+0

這是一個很好的解決方案,不幸的是,它只適用於「ActivityUnitTestCase」,但不適用於功能測試用例。 – 2013-06-27 09:44:58

+0

是的,我同意。我還發現捕獲多個Intents也是不可能的,例如,我的Activity可能會將某個啓動條件上的Intent發送給IntentService,然後在用戶按下按鈕時啓動另一個IntentService。不可能全部抓住。 – 2013-07-01 18:25:38

1

或者,你可以重新因子你的代碼,爲了做到「乾淨」的單元測試(我的意思是擁有一切嘲笑了除被測類單元測試)。實際上,我自己也有一種情況,我得到一個java.lang.RuntimeException: Stub!,因爲我想單元測試的代碼創建了一個包含我注入的mock的新Intents。

我考慮爲意圖創建自己的工廠。然後,我可以注入嘲笑出廠到我的課被測:

public class MyClassToBeTested { 
    public MyClassToBeTested(IntentFactory intentFactory) { 
     //assign intentFactory to field 
    } 
    .... 
    public void myMethodToTestUsingIntents() { 
     Intent i = intentFactory.create(); 
     i.setAction(AppConstants.INTENT_ACTION_PASSCODE_INPUT); 
     //when doing unit test, inject a mocked version of the 
     //IntentFactory and do the necessary verification afterwards. 
     .... 
    } 
} 

我的情況是不一樣的你,但我相信你可以申請一個工廠模式來解決它。我更願意編寫代碼來支持真正的單元測試,但必須承認您的解決方案非常聰明。

相關問題