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

Yo puedo llamar a la instrumentación del callActivityOn… a los métodos de la actividad existente, pero ¿cómo puedo activar la actividad de recreación, de manera que la actividad del OnCreate obtiene el bundle con el estado guardado

InformationsquelleAutor mfeingold | 2012-02-22

7 Comentarios

  1. 9

    He encontrado que este código causa nueva Actividad en la creación de:

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

    Pero esto no causa onSaveInstanceState a ser llamado. Así, por ejemplo, para probar si la actividad es propely creado después de ver cambio de la orientación de dicha prueba se debe hacer es:

    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);
        }
    });
  2. 6

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

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

    ActivityInstrumentationTestCase2.getActivity() se inicia la Actividad de la primera vez que la llame, pero luego simplemente devuelve la misma Actividad en cada llamada posterior en el caso de prueba. Por lo tanto, usted todavía está buscando en la Actividad que has terminado.

    Después de finalizar la primera Actividad, usted necesita para comenzar de nuevo a partir de la prueba. Usted puede utilizar InstrumentationTestCase.launchActivity(), por ejemplo.

    Como otro ejemplo, he escrito una prueba que empuja un botón en ActivityA que lanza ActivityB para-resultado; la prueba, a continuación, inmediatamente mata ActivityA (a través de un cambio de orientación, pero finish() iba a funcionar, también), y luego la prueba obtiene un identificador para el nuevo ActivityA que el sistema crea cuando ActivityB se realiza y envía su resultado. El truco no era la prueba de añadir una Instrumentación.ActivityMonitor y luego tener que espera del monitor para que el sistema inicie el nuevo ActivityA y dar la prueba de un identificador.

    EDITAR 2/23/2012 cdhabecker, Añadiendo reproducible código:

    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: (el sleep() llama a dar a la actividad de un montón de 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) {
            }
        }
    }

    De registro:

    02-23 21:25:37.689: I/Verbose(17747): onCreate() com.scanillion.demo.[email protected]
    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.[email protected]
    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.[email protected]
    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)

    Nota que finish() causado onDestroy(), pero la posterior getActivity() era un no-op. No sólo getActivity() no crear una instancia de una nueva Actividad, no incluso recrear el original.

    • ¿Puede usted proporcionar una referencia sólida para apoyar su declaración de «es simplemente devuelve la misma Actividad en cada llamada posterior en el caso de prueba«? Por CIERTO, creo que el punto clave aquí es por la Actividad de llamadas.finish() que va a destruir por completo que la actividad con la entrada del usuario estado, el código de prueba en mi respuesta es utilizado para comprobar si los Ahorro de la actividad del estado se aplique correctamente en la Actividad.onCreate(), no importa si la misma instancia (supongo basado en su estado de cuenta, aunque con diferente estado) se devuelve.
    • He añadido un reproducible caso.
    • Todavía no lo consigo por qué Thread.sleep(5000L) ha causado onStop() > onDestroy() recibir llamadas después de finish(). El sleep() truco también funciona bien para mí, ya que me esperan onStop() y onDestroy() sea llamado.
  3. 3

    Confirmo que cdhabecker es derecho, getActivity() devuelve la actividad, que se creó en el principio, incluso si «acabado» de ella. Pero creo que he encontrado una solución a prueba la recreación de la actividad. Usted puede tratar de solicitud de cambio de orientación. Este va a recrear su actividad, y, a continuación, recuperar recién creado. Fragmento de 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, no va a funcionar si usted evitar que su actividad de ser destruido después del cambio de orientación. Aquí usted puede encontrar mi respuesta completa con los mensajes de registro incluido. Espero que ayude. Saludos!

    • hmmm.. esto sólo podría funcionar… todavía se siente como un parche
  4. 1

    Si tienes un Android 4.x dispositivo, usted puede ir a Ajustes > opciones de Desarrollador y de VERIFICACIÓN «no mantener actividades». Ahora siempre que su Actividad pierde el foco (ex: botón de INICIO), va a ser asesinado y onSaveInstanceState(…) será llamado.

    Al reanudar su aplicación, su Actividad debe tener paquete de datos en el onCreate(…) método si la guardó en onSaveInstanceState(…).

    • Bueno, esto podría funcionar para el manual de pruebas. Estoy buscando una manera de hacerlo en la realización de pruebas automatizadas
  5. 1

    Hay un ejemplo muy bueno en el oficial dev guía de hablar acerca de la administración del estado de las pruebas de aquí. Básicamente, usted sólo necesita llamar a la Actividad.finish() para emular la actividad ha sido asesinado, echa un vistazo pseudo código de abajo:

    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.

    • No creo que esta respuesta obras-usted encontrará que getActivity() no iniciar una nueva actividad, la misma que tenía antes. Consulte stackoverflow.com/a/9422946/424529 para un enfoque diferente.
    • Pensé inicialmente que esta es la respuesta, resultó que estaba equivocado – ver el comentario de @cdhabecker
  6. 1

    La elaboración de cdhabecker la respuesta, he creado 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, yo destruirlo y restablecer llamando

    activity.finish();
    setActivity(null);

    en mi ActivityInstrumentationTestCase2 clase.

  7. 0

    Usted puede conseguir de nuevo retomó la Actividad a través de ActivityLifeCycleMonitor

    Por ejemplo, este método de esperar y establece un nuevo creado Activity 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 la Actividad de recreación en la rotación como este :

    Activity activity = getActivity(); //old activity    
    //rotate it
    activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
    //set new Activity
    waitAndSetResumedActivity();
    activity = getActivity();  //New Activity

Dejar respuesta

Please enter your comment!
Please enter your name here