test - Probando el código de Android con JUnit y el JDK
unit test android (5)
Estoy escribiendo algunas pruebas POJO para mi código de Android.
Quiero ejecutarlos localmente con el JDK (no con Dalvik en el emulador) - por velocidad, JUnit 4, Mockito, y poder ejecutar sin cabeza sin un dispositivo - entonces tengo un proyecto "Java" separado en Eclipse.
Si el método que estoy probando hace referencia a cualquier cosa desde el SDK de Android, por ejemplo, android.util.Log
, la prueba falla; esto tiene sentido porque android.jar
no se encuentra en el classpath. Para reproducir tengo este caso de prueba:
public class FooTests {
@Test
public void testFoo() {
android.util.Log.d("x", "y");
}
}
Si agrego android.jar
explícitamente al classpath del proyecto de prueba, obtengo excepciones como
java.lang.RuntimeException: Stub!
at android.util.Log.d(Log.java:7)
at com.example.FooTests.testFoo(FooTests.java:39)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
...
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
¿Hay alguna manera de hacer que el código funcione sin burlarse hasta el último bit de la dependencia de Android SDK? ¿Tal vez ya existe un android.jar
ridículo?
EDITAR : por ahora terminé envolviendo clases como android.util.Log
e inyectándolas en las instancias, para pruebas clásicas basadas en IOC. La sugerencia de PowerMock de Scott es mi próximo paso cuando lo necesite.
EDICION POSTERIOR : ¡ Robolectric !
¿No harán las pruebas incrustadas de android / junit lo que quieres?
No hay burlado android.jar que yo sepa. Yo uso Powermock para burlar todo. Una cosa que puedes hacer para ayudar con la burla pesada es hacer que tus clases ampliadas de Android como actividad, fragmentos, locutores, etc. sean delgadas y hacer que deleguen en clases de pojo. Podrías tomar una decisión basada en el riesgo para no aislar la unidad de prueba de las clases ampliadas de Android, y en su lugar, la unidad de integración probarlas a través del framework de pruebas de Android u otra cosa como Robotium.
Para las verdaderas pruebas de unidades de aislamiento en Android, para mí las pruebas unitarias en java jvm burlando a todas las clases colaboradoras es la mejor manera de hacerlo.
Yo tuve el mismo problema. Quería probar POJOs simples localmente.
Específicamente, mi código quería usar android.util.Base64.
Lo que terminé haciendo fue usar el SDK para instalar las fuentes de Android 4, y copié la clase android.util.Base64 a mi proyecto.
Sorprendentemente, esto funcionó.
unmock-plugin podría ayudar a https://github.com/bjoernQ/unmock-plugin . En mi caso, funciona con SparseArray.
Yo tuve el mismo problema. Quería probar lógica empresarial simple localmente. Específicamente, mi código usa android.util.SparseArray<E>
.
Probé 3 enfoques diferentes para que sea comprobable con junit fuera de Android.
- En mi lógica comercial, creé una interfaz y la
MySparseArray<E>
aMySparseArray<E>
que hereda deSparseArray<E>
. En la prueba junit reimplanté la interfaz usandoHashMap<Integer, E>
. Esto funciona, pero a la larga esto es mucho trabajo para hacer que la lógica de negocios sea comprobable por unidad si se requieren otrosandroid.*
. - Tal como lo sugirió @Tal Weiss, agregué las fuentes java de Android de las clases requeridas:
android.util.SparseArray.java
que usacom.android.internal.util.ArrayUtils.java
. Esto también funciona, pero no me gusta agregar más fuentes de Android, especialmente si hay muchas más dependencias - Descargué un archivo binario libre
android.jar
para un antiguo android 2.2 de http://grepcode.com/snapshot/repository.grepcode.com/java/ext/com.google.android/android/2.2_r1.1 y lo incluí como lib en mi proyecto junit-java. Este archivo contiene solo clases para los espacios de nombresandroid.*
com.android.*
,dalvik.*
,dalvik.*
Yframework.base.*
. Esto también funciona
En la actualidad, he logrado evitar el uso de las clases android.*
excepto SparseArray<E>
en la capa de mi empresa y no tengo ninguna dependencia con Contexto, Actividad o Servicio. Podría haber usado HashMap<Integer, E>
en la capa android-business en lugar de SparseArray<E>
.