ActivityUnitTestCase arroja RuntimeException cuando se ejecuta con AndroidJUnitRunner

Estoy intentando integrar AndoridJUnitRunner de Espresso 2.0 con ActivityUnitTestCase. Sin embargo, mis pruebas se estropean cuando startActivity () intenta inicializar mMockParent = new MockParent () .

Esto es lo que hice:

Cree un nuevo proyecto con Intellij 14 CE y realice algunos cambios en build.gradle.

android{ defaultConfig { applicationId "com.noob.testing" minSdkVersion 9 targetSdkVersion 21 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } compileOptions { sourceCompatibility JavaVersion.VERSION_1_7 targetCompatibility JavaVersion.VERSION_1_7 } } dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) compile 'com.android.support:appcompat-v7:21.0.+' androidTestCompile('org.mockito:mockito-core:1.9.5') androidTestCompile('com.google.dexmaker:dexmaker:1.2') androidTestCompile('com.google.dexmaker:dexmaker-mockito:1.2') androidTestCompile('com.android.support.test.espresso:espresso-core:2.0') androidTestCompile('com.android.support.test:testing-support-lib:0.1') } 

Escriba una prueba de unidad de estilo JUnit4.

 @RunWith(AndroidJUnit4.class) public class MainActivityJUnit4Test extends ActivityUnitTestCase<MainActivity> { public MainActivityJUnit4Test() { super(MainActivity.class); } MainActivity activity; @Before public void setup() throws Exception { injectInstrumentation(InstrumentationRegistry.getInstrumentation()); super.setUp(); ContextThemeWrapper context = new ContextThemeWrapper(getInstrumentation().getTargetContext(), R.style.AppTheme); setActivityContext(context); activity = startActivity(new Intent(Intent.ACTION_MAIN), null, null); } @Test public void baseCase() { TextView tv = (TextView) activity.findViewById(R.id.tv); Assert.assertEquals("Hello World", tv.getText()); } } 

Ejecute la prueba, obteniendo una traza de pila.

 junit.framework.AssertionFailedError at junit.framework.Assert.fail(Assert.java:48) at junit.framework.Assert.assertTrue(Assert.java:20) at junit.framework.Assert.assertNotNull(Assert.java:218) at junit.framework.Assert.assertNotNull(Assert.java:211) at android.test.ActivityUnitTestCase.startActivity(ActivityUnitTestCase.java:147) at com.sdchang.testing.MainActivityJUnit4Test.setup(MainActivityJUnit4Test.java:32) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:525) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42) at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:27) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:68) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222) at org.junit.runners.ParentRunner.run(ParentRunner.java:300) at org.junit.runners.Suite.runChild(Suite.java:128) at org.junit.runners.Suite.runChild(Suite.java:24) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222) at org.junit.runners.ParentRunner.run(ParentRunner.java:300) at org.junit.runner.JUnitCore.run(JUnitCore.java:157) at org.junit.runner.JUnitCore.run(JUnitCore.java:136) at android.support.test.runner.AndroidJUnitRunner.onStart(AndroidJUnitRunner.java:270) at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1701) 

Este rastro de pila es en realidad un

 java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare() 

Que se produce cuando startActivity () intenta inicializar mMockParent = new MockParent () :

  ComponentName cn = new ComponentName(mActivityClass.getPackage().getName(), mActivityClass.getName()); intent.setComponent(cn); ActivityInfo info = new ActivityInfo(); CharSequence title = mActivityClass.getName(); mMockParent = new MockParent(); String id = null; 

¿Estoy perdiendo algo más para que AndroidJUnitRunner funcione con ActivityUnitTestCase? Cualquier ayuda sería muy apreciada.

Después de golpear mi cabeza contra la pared, ventanas y varios muebles, finalmente conseguí mis pruebas de trabajo!

A partir de una respuesta en su seguimiento de problemas , aprendí que no se pueden crear nuevos Handlers desde el hilo de instrumentación. Lo que significa startActivity () debe ser invocado en el subproceso de la interfaz de usuario. Lo que lleva a 3 soluciones.

1.Use Instrumentation's runOnMainSync()

 getInstrumentation().runOnMainSync(new Runnable() { @Override public void run() { activity = startActivity(new Intent(Intent.ACTION_MAIN), null, null); } }); 

2.Create su propia clase base que extiende ActivityUnitTestCase y reemplazar startActivity

 @Override protected T startActivity(final Intent intent, final Bundle savedInstanceState, final Object lastNonConfigurationInstance) { return startActivityOnMainThread(intent, savedInstanceState, lastNonConfigurationInstance); } private T startActivityOnMainThread(final Intent intent, final Bundle savedInstanceState, final Object lastNonConfigurationInstance) { final AtomicReference<T> activityRef = new AtomicReference<>(); final Runnable activityRunnable = new Runnable() { @Override public void run() { activityRef.set(YourBaseActivityUnitTestCase.super.startActivity( intent, savedInstanceState, lastNonConfigurationInstance)); } }; if (Looper.myLooper() != Looper.getMainLooper()) { getInstrumentation().runOnMainSync(activityRunnable); } else { activityRunnable.run(); } return activityRef.get(); } 

3. Si llama a startActivity () en un método de prueba y toda su prueba puede ejecutarse en el hilo principal, simplemente puede anotar su método de prueba con @UiThreadTest.

En mis pruebas, he probado todas las 3 soluciones, pero solo 1 & 2 funcionará .

  • Servicios Roboeléctricos y de Intención
  • ¿Por qué obtengo un NoClassDefFoundError al ejecutar mi prueba en ActionBarActivity?
  • Robolectric buildActivity () con espía Mockito?
  • Gradle - equivalente de test {} bloque de configuración para android
  • Soporte de la clase Robolectric de Android. Cómo tener las referencias de la clase de biblioteca R desde el proyecto de aplicación
  • Eliminación de contactos (crudos) en Android 2.x
  • Cómo correctamente mock HttpGet llamada en la prueba de Android
  • Cómo deshabilitar las pruebas de unidad de estudio de Android (androidTest)
  • Pruebas de unidades de Android fallan para tipo de compilación de depuración
  • ¿Existe una manera de escribir una prueba de unidad para una API de destino
  • Android, Gradle. Cómo construir aplicaciones y ejecutar pruebas desde la aplicación de prueba
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.