2012-04-27 13 views
7

¿Cómo puedo crear el caso de prueba JUnit de Android que prueba el contenido de una intención generada dentro de una actividad?¿Cómo puedo probar la unidad una intención lanzada/enviada desde una actividad?

Tengo una actividad que contiene una ventana EditText, y cuando el usuario ha terminado de ingresar los datos requeridos, la actividad inicia un IntentService que registra los datos y continúa con el proceso de la aplicación. Aquí está la clase quiero poner a prueba, la OnEditorActionListener/PasscodeEditorListener se crea como una clase separada:

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

¿Cómo puedo interceptar las dos posibles Intentos salientes generados por la actividad y verificar su contenido?

Gracias

+0

¿Estás usando el simulater? Tal vez me estoy perdiendo algo, pero ¿no puedes probarlo de esa manera? – Nick

+0

He estado usando tanto el simulador como el teléfono, aunque no creo que deba haber una diferencia. He visto varias formas de inyectar Intents en cualquier Actividad en particular bajo prueba, pero no muchas maneras de ver el resultado. Vimos otra publicación donde configuraron ContextWrapper e interceptaron la llamada a "startService()". Esto funciona para la primera llamada, pero no para llamadas posteriores. Una actividad puede lanzar múltiples intentos sin cerrar, estoy interesado en verlos/probarlos todos. –

Respuesta

6

que pensé cómo utilizar ContextWrapper con la ayuda de otro sitio web.

Utilice ContextWrapper y anule todas las funciones de intento. Al generalizar todas mis pruebas de actividad, amplié la clase ActivityUnitTestCase e implementé la solución como un shim. Disfrutar de:

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

Esa es una buena solución, lamentablemente solo funciona con 'ActivityUnitTestCase', pero no con casos de prueba funcionales. –

+0

Sí, estoy de acuerdo. También descubrí que no es posible detectar varios Intents, por ejemplo, mi actividad puede enviar un Intent en algunas condiciones de arranque a un IntentService, luego iniciar otro cuando el usuario presiona un botón. No es posible atrapar a todos. –

1

Como alternativa, puede volver a factor de su código con el fin de hacer unidad de prueba "limpia" (me refiero a una prueba de unidad que tiene todo burlado a cabo, excepto la clase bajo prueba). En realidad, yo mismo tengo una situación en la que obtengo un java.lang.RuntimeException: Stub! porque el código que deseo probar en unidad crea nuevos Intents que contienen burlas que he inyectado.

Considero crear mi propia fábrica para propósitos. Entonces podría inyectar una fábrica burlado a mi prueba de clase-bajo-:

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

Mi situación no es la misma que la suya, pero creo que se podría aplicar una fábrica de patrón de resolverlo también. Prefiero escribir código para admitir pruebas unitarias verdaderas, pero debo admitir que su solución es bastante inteligente.

Cuestiones relacionadas