GetActivity () causa RuntimeException: No se pudo iniciar intención Intent act = android.intent.action.MAIN

Actualizado # 1: más información agregada al final de esta publicación

Soy nuevo en el desarrollo y las pruebas de Android.

Tengo tres exámenes Espresso. La primera prueba pasa, pero la segunda no se ejecutará porque la llamada a getActivity () en el método setUp () antes de la segunda prueba siempre falla:

Blockquote java.lang.RuntimeException: No se pudo iniciar intención Intent {act = android.intent.action.MAIN flg = 0x10000000 cmp = mi.nombre de archivo / .ActivityMain} en 45 segundos. …

La tercera prueba pasa.

No tengo operaciones largas de funcionamiento, animaciones o llamadas de red en la creación. Puedo hacer clic en todos los elementos del menú de mi aplicación repitiendo manualmente el flujo de prueba sin problemas.

Por alguna razón, la primera prueba "rompe" la próxima llamada getActivity () en setUp () antes de la segunda prueba. Todas las pruebas siguientes (después de la segunda prueba) correrán bien.

He encontrado una pregunta similar , pero parece que no se resolvió y tiene un problema un poco diferente.

Código de prueba:

import static com.google.android.apps.common.testing.ui.espresso.Espresso.onData; import static com.google.android.apps.common.testing.ui.espresso.Espresso.onView; import static com.google.android.apps.common.testing.ui.espresso.Espresso.openActionBarOverflowOrOptionsMenu; import static com.google.android.apps.common.testing.ui.espresso.action.ViewActions.click; import static com.google.android.apps.common.testing.ui.espresso.assertion.ViewAssertions.matches; import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.isDisplayed; import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.withId; import static com.google.android.apps.common.testing.ui.espresso.matcher.ViewMatchers.withText; import static org.hamcrest.Matchers.allOf; import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.Matchers.is; import net.humblegames.bodylasticscalculator.ActivityMain; import net.humblegames.bodylasticscalculator.R; import net.humblegames.bodylasticscalculator.applogic.BandSystem; import org.hamcrest.BaseMatcher; import org.hamcrest.Description; import org.hamcrest.Matcher; import org.junit.After; import org.junit.Before; import android.app.Activity; import android.test.ActivityInstrumentationTestCase2; import android.util.Log; public class MenuNavigationTestExperiment extends ActivityInstrumentationTestCase2<ActivityMain> { private String TAG = getClass().getSimpleName(); private Activity activity; public MenuNavigationTestExperiment() { super(ActivityMain.class); } @Before public void setUp() throws Exception { Log.d(TAG, "SETUP"); activity = getActivity(); super.setUp(); } @After public void tearDown() throws Exception { Log.d(TAG, "TEARDOWN"); super.tearDown(); } public void testFirst() { Log.d(TAG, "testFirst"); clickMenuItem("Select band system"); onData(allOf(is(instanceOf(BandSystem.class)), hasName("MMA Training"))) .onChildView(withId(R.id.label)).perform(click()); clickMenuItem("About"); onView(withId(R.id.about_webview)).check(matches(isDisplayed())); } public void testSecond() { Log.d(TAG, "testSecond"); // this test will not run } public void testThird() { Log.d(TAG, "testThird"); // this test will pass } // ------------------ HELPER METHODS --------------------------------------- private void clickMenuItem(String menuItem) { Log.d(TAG, "clickMenuItem"); openActionBarOverflowOrOptionsMenu(getInstrumentation() .getTargetContext()); onView(withText(menuItem)).perform(click()); } private Matcher<BandSystem> hasName(final String name) { Log.d(TAG, "hasName"); return new BaseMatcher<BandSystem>() { @Override public boolean matches(final Object item) { final BandSystem foo = (BandSystem) item; return name == foo.getName(); } @Override public void describeTo(final Description description) { description.appendText("getName should return ").appendValue( name); } }; } } 

Rastreo de error:

 java.lang.RuntimeException: Could not launch intent Intent { act=android.intent.action.MAIN flg=0x10000000 cmp=net.humblegames.bodylasticscalculator/.ActivityMain } within 45 seconds. Perhaps the main thread has not gone idle within a reasonable amount of time? There could be an animation or something constantly repainting the screen. Or the activity is doing network calls on creation? See the threaddump logs. For your reference the last time the event queue was idle before your activity launch request was 1395582828351 and and now the last time the queue went idle was: 1395582830169. If these numbers are the same your activity might be hogging the event queue. at com.google.android.apps.common.testing.testrunner.GoogleInstrumentation.startActivitySync(GoogleInstrumentation.java:277) at android.test.InstrumentationTestCase.launchActivityWithIntent(InstrumentationTestCase.java:119) at android.test.InstrumentationTestCase.launchActivity(InstrumentationTestCase.java:97) at android.test.ActivityInstrumentationTestCase2.getActivity(ActivityInstrumentationTestCase2.java:104) at net.humblegames.bodylasticscalculator.test.MenuNavigationTestExperiment.setUp(MenuNavigationTestExperiment.java:42) at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:191) at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:176) at android.test.InstrumentationTestRunner.onStart(InstrumentationTestRunner.java:554) at com.google.android.apps.common.testing.testrunner.GoogleInstrumentationTestRunner.onStart(GoogleInstrumentationTestRunner.java:167) at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1701) 


Actualización # 1

Creé un proyecto de eclipse limpio y una prueba de Espresso limpia para ese proyecto. Pude reproducir el mismo error durante la ejecución de prueba de Espresso (pero todavía no estoy seguro si la causa de este error es la misma en mi aplicación real):

La aplicación de destino tiene 3 actividades (principal, segunda y tercera). El usuario navega entre ellos haciendo clic en los elementos del menú: la actividad principal comienza la segunda, la segunda inicia la tercera.

Encontré que si llamo clickMenuItem () (ver abajo) Y Thread.sleep (500) en la primera prueba esto causa falla en setUp () en getActivity () llamada antes de la segunda prueba. Si el tiempo de espera en el sueño es inferior a 0,5 segundos, no hay ningún fallo.

Al mismo tiempo, si llama Thread.sleep (10000) y no llama a clickMenuItem () no hay bloqueo también. Duerrá con éxito durante 10 segundos en la primera prueba y también pasará la segunda.


Código de prueba:

 public class MainActivityTest extends ActivityInstrumentationTestCase2<MainActivity> { private String TAG = getClass().getSimpleName(); private Activity activity; public MainActivityTest() { super(MainActivity.class); } public void setUp() throws Exception { Log.d(TAG, "SETUP"); activity = getActivity(); super.setUp(); } public void tearDown() throws Exception { Log.d(TAG, "TEARDOWN"); super.tearDown(); } public void testFirst() throws InterruptedException { Log.d(TAG, "testFirst"); clickMenuItem("Start second activity"); clickMenuItem("Start third activity"); Thread.sleep(500); } public void testSecond() { Log.d(TAG, "testSecond"); // this test will not run } private void clickMenuItem(String menuItem) { Log.d(TAG, "clickMenuItem"); openActionBarOverflowOrOptionsMenu(getInstrumentation() .getTargetContext()); onView(withText(menuItem)).perform(click()); } } 


Código objetivo:

Actividad principal:

 public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle item selection switch (item.getItemId()) { case R.id.action_start_second_activity: Intent intent = new Intent(this, SecondActivity.class); startActivity(intent); return true; default: return super.onOptionsItemSelected(item); } } } 

Segunda actividad:

 public class SecondActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_second); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.second, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle item selection switch (item.getItemId()) { case R.id.action_start_third_activity: Intent intent = new Intent(this, ThirdActivity.class); startActivity(intent); return true; default: return super.onOptionsItemSelected(item); } } } 

Tercera Actividad:

 public class ThirdActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_third); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.third, menu); return true; } } 

Encontré una solución. He añadido el código que golpea el botón de nuevo varias veces en el método tearDown () para cerrar todas las actividades abiertas anteriormente. Desafortunadamente no encontré otro método para cerrar todas las actividades abiertas en Espresso. Robotium tiene un método muy conveniente para ese propósito solo.finishOpenedActivities ().

 public void tearDown() throws Exception { Log.d(TAG, "TEARDOWN"); goBackN(); super.tearDown(); } private void goBackN() { final int N = 10; // how many times to hit back button try { for (int i = 0; i < N; i++) Espresso.pressBack(); } catch (com.google.android.apps.common.testing.ui.espresso.NoActivityResumedException e) { Log.e(TAG, "Closed all activities", e); } } 

La solución pressBack no funcionó para mí, pero encontré otra:

 @Override protected void tearDown() throws Exception { closeAllActivities(getInstrumentation()); super.tearDown(); } public static void closeAllActivities(Instrumentation instrumentation) throws Exception { final int NUMBER_OF_RETRIES = 100; int i = 0; while (closeActivity(instrumentation)) { if (i++ > NUMBER_OF_RETRIES) { throw new AssertionError("Limit of retries excesses"); } Thread.sleep(200); } } public static <X> X callOnMainSync(Instrumentation instrumentation, final Callable<X> callable) throws Exception { final AtomicReference<X> retAtomic = new AtomicReference<>(); final AtomicReference<Throwable> exceptionAtomic = new AtomicReference<>(); instrumentation.runOnMainSync(new Runnable() { @Override public void run() { try { retAtomic.set(callable.call()); } catch (Throwable e) { exceptionAtomic.set(e); } } }); final Throwable exception = exceptionAtomic.get(); if (exception != null) { Throwables.propagateIfInstanceOf(exception, Exception.class); Throwables.propagate(exception); } return retAtomic.get(); } public static Set<Activity> getActivitiesInStages(Stage... stages) { final Set<Activity> activities = Sets.newHashSet(); final ActivityLifecycleMonitor instance = ActivityLifecycleMonitorRegistry.getInstance(); for (Stage stage : stages) { final Collection<Activity> activitiesInStage = instance.getActivitiesInStage(stage); if (activitiesInStage != null) { activities.addAll(activitiesInStage); } } return activities; } private static boolean closeActivity(Instrumentation instrumentation) throws Exception { final Boolean activityClosed = callOnMainSync(instrumentation, new Callable<Boolean>() { @Override public Boolean call() throws Exception { final Set<Activity> activities = getActivitiesInStages(Stage.RESUMED, Stage.STARTED, Stage.PAUSED, Stage.STOPPED, Stage.CREATED); activities.removeAll(getActivitiesInStages(Stage.DESTROYED)); if (activities.size() > 0) { final Activity activity = activities.iterator().next(); activity.finish(); return true; } else { return false; } } }); if (activityClosed) { instrumentation.waitForIdleSync(); } return activityClosed; } 

Esto parece funcionar para mí para cerrar todas las actividades en la pila, excepto la primera.

  @After @Override public void tearDown() throws Exception { Intent intent = new Intent(getActivity(), getActivity().getClass()); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); // Removes other Activities from stack intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); myActivity.startActivity(intent); super.tearDown(); } 

Pruebe lo siguiente:

 @Before public void setUp() throws Exception { super.setUp(); Log.d(TAG, "SETUP"); activity = getActivity(); } 

Es trabajo para mí:

 androidTestCompile ('com.android.support.test.espresso:espresso-contrib:2.2'){ exclude group: 'com.android.support', module: 'appcompat' exclude group: 'com.android.support', module: 'support-v4' exclude module: 'recyclerview-v7' 

}

  • Uso de Espresso para hacer clic en la vista dentro del elemento RecyclerView
  • Pruebas de Android: UIAutomator vs Espresso
  • Haciendo clic en un elemento de menú en la barra de acción con Espresso al usar onView (withId (...))
  • Prueba de ViewPager con múltiples fragmentos usando espresso android
  • Compruebe el texto en la posición en el reciclador
  • Crear DummyActivity dentro de la carpeta androidTest para probar
  • ¿Cómo obtener una vista desde dentro de Espresso para pasar a un IdlingResource?
  • ¿Cómo podemos usar espresso para probar una actividad de configuración de Android con un PreferenceFragment?
  • Espresso: Recyclerview scroll to end
  • Android: activar un botón
  • Android Error Clase ref en clase pre-verificada resuelta a implementación inesperada
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.