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:
- Acceso a recursos en un proyecto de prueba de Android
- `RenamingDelegatingContext` está obsoleto. ¿Cómo probamos SQLite db ahora?
- Automatización de la caja de prueba de la unidad Android: biblioteca Robolectric vs marco de pruebas de Android
- Enviar Tecla Intro usando robotium para pruebas de Android?
- Prioridad de hilo: 'prueba de unidad'
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.
- ¿Cómo probar mejor el código Looper y Handler de la unidad en Android?
- ¿Puedo usar Cobertura en pruebas de unidad con PowerMock?
- ¿Por qué Robotium es más lento cuando realiza tareas sencillas de interfaz de usuario en comparación con el código nativo de Android?
- ¿Cuál es la forma más rápida de ejecutar pruebas de unidad en Android
- Ejecución de una prueba de unidad específica con gradle
- Cobertura de código con jacoco para una biblioteca de Android
- Prueba de unidad de Android con Retrofit2 y Mockito o Robolectric
- ¿Cómo forzar un cambio de configuración en una prueba Android Robolectric?
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á .
- ¿Cómo ejecutar mi código Go en Android?
- Cómo puedo descargar imágenes de google play developer console