Prueba de unidad de ciclo de vida de actividad

En una prueba de unidad de actividad, ¿cómo puedo emular los eventos del ciclo de vida de la actividad?

Puedo llamar a la instrumentación callActivityOn … métodos sobre la actividad existente, pero ¿cómo puedo activar la recreación de la actividad para que OnCreate de la actividad recibe el paquete con el estado guardado

He encontrado que este código causa la creación de una nueva actividad:

myActivity.finish(); setActivity(null); myActivity = getActivity(); 

Pero esto no causa que onSaveInstanceState sea llamado. Por ejemplo, para probar si la actividad se crea propiamente después de cambiar la orientación de la vista, dicha prueba debería hacerlo:

 private mInstrumentation = getInstrumentation(); ... final Bundle outState = new Bundle(); mInstrumentation.callActivityOnSaveInstanceState(mActivity, outState); mActivity.finish(); setActivity(null); mActivity = getActivity(); runTestOnUiThread(new Thread() { @Override public void run() { mInstrumentation.callActivityOnRestoreInstanceState(mActivity, outState); } }); 

No siga el ejemplo de prueba de administración de estado : {link muerto}

 myActivity.finish(); myActivity = getActivity(); 

ActivityInstrumentationTestCase2.getActivity() inicia la Actividad la primera vez que la llame, pero luego simplemente devuelve esa misma Actividad en cada llamada posterior en el caso de prueba. Por lo tanto, usted todavía está mirando la actividad que usted terminó.

Después de terminar la primera Actividad, debe iniciar una nueva desde la prueba. Puede utilizar InstrumentationTestCase.launchActivity() , por ejemplo.

Como otro ejemplo, he escrito una prueba que empuja un botón en ActivityA que lanza ActivityB for-result; La prueba mata inmediatamente a ActivityA (a través de un cambio de orientación, pero finish () también funcionaría), y luego la prueba obtiene un identificador a la nueva ActivityA que el sistema crea cuando ActivityB se hace y envía su resultado. El truco allí era tener la prueba agrega un Instrumentation.ActivityMonitor y entonces tener ese monitor esperar el sistema para comenzar el nuevo ActivityA y dar a la prueba un asidero a él.

EDIT 2/23/2012 cdhabecker, Agregando código reproducible:

 public class VerboseActivity extends Activity { public final static String TAG = "Verbose"; @Override protected void onCreate(Bundle savedInstanceState) { Log.i(TAG, "onCreate() " + (Activity)this); super.onCreate(savedInstanceState); setContentView(R.layout.activity5); } @Override protected void onDestroy() { Log.i(TAG, "onDestroy()."); super.onDestroy(); } } 

Caso de prueba: (las llamadas sleep () dan a la actividad mucho tiempo para responder)

 public class VerboseTest extends ActivityInstrumentationTestCase2<VerboseActivity> { Activity myActivity = null; public VerboseTest() { super("com.scanillion.demo", VerboseActivity.class); } public void test_01() { String TAG = "test_01"; myActivity = getActivity(); Log.i(TAG, "A getActivity()=" + myActivity); myActivity.finish(); try { Thread.sleep(5000L); } catch (InterruptedException e) { } myActivity = getActivity(); Log.i(TAG, "B getActivity()=" + myActivity); try { Thread.sleep(5000L); } catch (InterruptedException e) { } } } 

Iniciar sesión:

 02-23 21:25:37.689: I/Verbose(17747): onCreate() com.scanillion.demo.VerboseActivity@43ba3360 02-23 21:25:38.159: I/ActivityManager(67): Displayed activity com.scanillion.demo/.VerboseActivity: 526 ms (total 526 ms) 02-23 21:25:38.180: I/test_01(17747): A getActivity()=com.scanillion.demo.VerboseActivity@43ba3360 02-23 21:25:38.540: I/Verbose(17747): onDestroy(). 02-23 21:25:43.236: I/test_01(17747): B getActivity()=com.scanillion.demo.VerboseActivity@43ba3360 02-23 21:25:48.439: I/TestRunner(17747): finished: test_01(com.scanillion.demo.test.VerboseTest) 02-23 21:25:48.439: I/TestRunner(17747): passed: test_01(com.scanillion.demo.test.VerboseTest) 

Tenga en cuenta que finish() causó onDestroy() , pero el siguiente getActivity() fue un no-op. No sólo getActivity () no instancia una nueva Actividad, ni siquiera vuelve a crear la original.

Confirmo que cdhabecker tiene razón, getActivity () devuelve la actividad que se creó al principio, incluso si la "terminaste". Pero creo que he encontrado una solución para probar la recreación de la actividad. Puede intentar solicitar un cambio de orientación. Esto volverá a crear su actividad y, a continuación, recuperará recién creado. Código siguiente: (he usado robotium ):

 protected void setUp() throws Exception { super.setUp(); mActivity = getActivity(); mSolo = new Solo(getInstrumentation(), getActivity()); Log.v(TAG, "setUp; activity=" + mActivity); } public void testOrienationChange(){ mSolo.setActivityOrientation(Solo.LANDSCAPE); getInstrumentation().waitForIdleSync(); MyActivity newActivity = getActivity(); //should be new, but it's not Activity newActivity2 = mSolo.getCurrentActivity(); //this will return newly created Log.v(TAG, "testOrienationChange; activity=" + newActivity); Log.v(TAG, "testOrienationChange; activity2=" + newActivity2); } 

Por supuesto que no funcionará si evita que su actividad sea destruida después de un cambio de orientación. Aquí puede encontrar mi respuesta completa con mensajes de registro incluidos. Espero que ayude. ¡Saludos!

Si tienes un dispositivo Android 4.x, puedes ir a Configuración> Opciones para desarrolladores y VERIFICAR "No mantener actividades". Ahora, cada vez que tu Actividad pierda el foco (por ejemplo, el botón HOME), se matará y se llamará onSaveInstanceState (…).

Cuando reanude su aplicación, su actividad debe tener datos de bundle en el método onCreate (…) si lo guardó en onSaveInstanceState (…).

Hay un muy buen ejemplo en el guía oficial de desarrollo que habla sobre las pruebas de gestión estatal aquí . Básicamente sólo tienes que llamar a Activity.finish () para emular la actividad se ha matado, echa un vistazo a pseudo código a continuación:

 public void testIfStateIsSaved() { // Open myActivity first time. MyActivity myActivity = getActivity(); final EditText editText = (EditText) myActivity.findViewById(com.company.R.id.edit_text); // emulate some user action myActivity.runOnUiThread(new Runnable() { public void run() { editText.setText("save me"); } }); // Suppose you have implemented saved state properly. // kill activity and restart it again. myActivity.finish(); myActivity = getActivity(); final EditText editText2 = (EditText) myActivity.findViewById(com.company.R.id.edit_text); assertEquals("user input must be saved", "save me", editText2.getText()); } 

Espero que esto ayude.

Elaborando la respuesta de cdhabecker, creé el siguiente método estático que funciona para mí:

 public static Activity restartActivity(Activity activity, Instrumentation instrumentation, Intent intent){ String className = activity.getClass().getName(); Instrumentation.ActivityMonitor monitor = instrumentation.addMonitor(className, null, false); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.setClassName(instrumentation.getTargetContext(), className ); instrumentation.startActivitySync(intent); Activity newActivity = instrumentation.waitForMonitor(monitor); instrumentation.removeMonitor(monitor); return newActivity; } 

Después de usar la actividad, la destruyo y la reinicio llamando

 activity.finish(); setActivity(null); 

En mi clase ActivityInstrumentationTestCase2.

Puede obtener nueva actividad reanudada a través de ActivityLifeCycleMonitor

Por ejemplo, este método espera y establece nueva Activity creada como actividad actual.

 public void waitAndSetResumedActivity() { // well at least there are some activities in the pipeline - lets see if they resume. long[] waitTimes = {10, 50, 100, 500, TimeUnit.SECONDS.toMillis(2), TimeUnit.SECONDS.toMillis(30)}; final ActivityLifecycleMonitor activityLifecycleMonitor = ActivityLifecycleMonitorRegistry.getInstance(); final AtomicBoolean activityResumed = new AtomicBoolean(false); for (int waitIdx = 0; waitIdx < waitTimes.length; waitIdx++) { if (activityResumed.get()) return; try { Thread.sleep(waitTimes[waitIdx]); } catch (InterruptedException e) { e.printStackTrace(); } getInstrumentation().runOnMainSync(new Runnable() { @Override public void run() { Collection<Activity> resumedActivities = activityLifecycleMonitor.getActivitiesInStage(Stage.RESUMED); if (!resumedActivities.isEmpty()) { activity = (MainActivity) resumedActivities.iterator().next(); setActivity(activity); activityResumed.set(true); } } }); } throw new NoActivityResumedException("No activities in stage RESUMED. Did you forget to " + "launch the activity. (test.getActivity() or similar)?"); } 

Así que después de llamar a este método, cualquier llamada a getActivity() devolverá la nueva Actividad.

Puede probar Recreación de actividad en rotación de la siguiente manera:

 Activity activity = getActivity(); // old activity //rotate it activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); //set new Activity waitAndSetResumedActivity(); activity = getActivity(); // New Activity 
  • Schedulers.immediate () no funciona con las pruebas de gradle de la línea de comandos
  • ¿La forma más simple de probar una unidad de una aplicación de la biblioteca de Android?
  • Mockito / Power Mockito: incapaz de obtener la salida esperada cuando el método de burla de LayoutParams en android
  • Valor de Stub de Build.VERSION.SDK_INT en la prueba de unidad local
  • Android compartió código generado entre test y androidTest
  • Android Studio simple Unidad de prueba no funciona
  • Cómo probar la interacción simulada en Activity onResume () ¿Utilizando Dagger Modules y Robolectric?
  • ¿Ejecutar pruebas de unidad android desde la línea de comandos?
  • Robolectric: 3.3.2 - Ningún fichero de manifiesto: build \ intermedios \ manifestos \ lleno \ debug \ src \ main \ AndroidManifest.xml
  • Cómo ejecutar todas las pruebas (unitarias e instrumentadas) con un solo clic en Android Studio
  • Android InstrumentationTestCase getFilesDir () devuelve null
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.