2012-04-27 6 views
7

Wie kann ich einen Android JUnit-Testfall erstellen, der den Inhalt einer in einer Aktivität generierten Absicht testet?Wie kann ich einen Intent testen, der von einer Aktivität gestartet/gesendet wurde?

Ich habe eine Aktivität, die ein EditText-Fenster enthält. Wenn der Benutzer die erforderlichen Daten eingegeben hat, startet die Aktivität einen Intent zu einem IntentService, der die Daten aufzeichnet und mit dem Anwendungsprozess fortfährt. Hier wird die Klasse I testen will, der OnEditorActionListener/PasscodeEditorListener wird als separate Klasse erstellt:

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; 
    } 
} 

Wie kann ich abfangen die beide möglichen abgehenden Intents durch die Aktivität erzeugt und dessen Inhalt überprüfen?

Dank

+0

Verwenden Sie den Simulator? Vielleicht vermisse ich etwas, aber kannst du es nicht einfach so testen? – Nick

+0

Ich habe sowohl den Simulator als auch den Handapparat benutzt, obwohl ich nicht denke, dass es einen Unterschied geben sollte. Ich habe eine Reihe von Möglichkeiten gesehen, Intents in eine bestimmte zu testende Aktivität zu injizieren, aber nicht viele Möglichkeiten, die Ausgabe zu beobachten. Habe einen anderen Beitrag gesehen als sie den ContextWrapper gesetzt und den Aufruf von "startService()" abgefangen haben. Dies funktioniert für den ersten Anruf, nicht jedoch für nachfolgende Anrufe. Eine Aktivität kann mehrere Absichten starten, ohne sie zu schließen. Ich möchte sie alle beobachten/testen. –

Antwort

6

Ich dachte, wie ContextWrapper mit Hilfe einer anderen Website zu nutzen.

Verwenden Sie ContextWrapper und überschreiben Sie alle Intent-Funktionen. Verallgemeinernd für alle meine Aktivitäts-Tests habe ich die ActivityUnitTestCase-Klasse erweitert und die Lösung als Shim implementiert. Genießen Sie:

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

Das ist eine nette Lösung, leider funktioniert es nur mit 'ActivityUnitTestCase's, aber nicht mit funktionalen Testfällen. –

+0

Ja, ich stimme zu. Ich habe auch festgestellt, dass das Abfangen mehrerer Intents auch nicht möglich ist, zum Beispiel kann meine Aktivität eine Intent bei einer Startbedingung an einen IntentService senden und dann eine andere starten, wenn der Benutzer eine Taste drückt. Nicht möglich, alles zu fangen. –

1

Alternativ könnten Sie Ihren Code, um erneut Faktor zu tun, „clean“ Unit-Test (ich meine einen Unit-Test, der alles verspottet, außer der Klasse unter Test hat). Eigentlich habe ich selbst eine Situation, wo ich eine java.lang.RuntimeException: Stub! bekomme, weil der Code, den ich testen will, neue Intents erzeugt, die Mocks enthalten, die ich injiziert habe.

Ich überlege, meine eigene Fabrik für Intents zu erstellen. Dann könnte ich ein verspottet aus Fabrik zu meiner Klasse-under-Test injizieren:

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. 
     .... 
    } 
} 

Meine Situation ist nicht das gleiche wie Sie, aber ich glaube, Sie könnten eine Fabrik-Muster anwenden es auch zu lösen. Ich schreibe lieber Code, um echte Komponententests zu unterstützen, muss aber zugeben, dass Ihre Lösung ziemlich clever ist.

Verwandte Themen