26. Espressoispowerful
We can interact with views (onView)
We can interact with data adapters
(onData)
Go back (pressBack)
Open menus
(openActionBarOverflowOrOptionsMenu and
openContextualActionModeOverflowMenu)
And check if the element is checked
(isChecked), can be clicked
(isClickable), is being displayed in the
screen (isDisplayed)...
Image courtesy of jesadaphorn at FreeDigitalPhotos.net
37. Summary
We have Unit tests (JVM) and Instrumentation Tests (Android
Device)
Add Unit test as much as possible.
Add mocks for your dependencies when needed.
ActivityTestRule to test activities controlling their
lifecycle.
ServiceTestRule to test Services controlling their
lifecycle (but not valid for IntentService)
Espresso IntentsTestRule to handle activities and stub and
verify intents
Cuando empiezas a trabajar de nuevas en un tema puede ser difícil encontrar la documentación adecuada. Google ha intentado mejorar eso sacando una serie de Codelabs cada año con motivo de su conferencia anual Google I/O en los que permite tocar temas muy diversos como Android, web, polymer. Uno de los cursos que sacaron este año fue Unit and UI Testing in Android Studio y en él se basa parte del material que voy a ir explicando. Si alguien quiere ir probando las cosas por sí mismo, puesto que sin duda haciendo las cosas una misma es como más se aprende.
En Android tenemos dos bloques grandes de tests que están muy diferenciados. Tenemos por un lado los tests unitarios, los cuales son simplemente típicos tess de Java que se ejecutan en la máquina virtual de java, con la característica de que gradle nos proporciona una implementación fake de las clases Android que por defecto lanza excepciones si invocas a métodos Android, ya que en este tipo de tests no deberíamos hacer uso de sus funciones. Por otro lado tenemos el bloque de los tests de instrumentación. Estos tests dependen completamente de Android y por lo tanto tienen que ejecutarse o bien en un dispositivo o bien en el emulador.
Vamos a empezar viendo los tests unitarios. Para configurar el entorno de AndroidStudio para trabajar con los tests unitarios necesitamos hacer tres cosas: 1. Seleccionar en el selector de Test Artifact de la ventana de Build Variants la opción de Test Unit. 2. A continuación creamos el árbol de carpetas test/java bajo la carpeta src. Para hacer esto tendremos que estar en la vista de Project puesto que con la vista de Android no veríamos el árbol completo. 3. El último paso que tenemos que hacer es añadir la dependencia a la librería de testing. Mi recomendación es usar junit 4 y la última versión estable que hay que es la 4.4. Para añadir la dependencias tenemos que añadir la llamada a testCompile con la librería dentro de las dependencias en nuestro fichero gradle.
Ahora que ya tenemos el proyecto configurado creamos una clase que será la que vamos a testear. En este ejemplo se trata de una calculadora. Para crear la clase de test podemos hacerlo manualmente o también desde la clase que queremos probar podemos acceder a la opción GoTo -> Test del menú contextual al pinchar sobre la clase.
Esa llamada nos va a lanzar un wizard sencillo que nos va a ayudar a generar la clase. Nos da la opción de seleccionar la librería de testing, el paquete, si queremos añadir métodos de setup y teardown y nos permite seleccionar los métodos de la clase que queremos testear.
Usando el wizard nos crearía una clase tal que así. Al haber seleccionado la opción de setUp generará el método setUp con la anotación Before donde podremos poner nuestro código de preparación para los tests y crea un método testSum para probar el método sum anotado con @Test. Pero ese nombre testSum no ayuda mucho
Durante unos años Google llevó a cabo una iniciativa que no sé si continúa llamada Testing on the Toilet. En ella se dedicaban a escribir una serie de panfletos con buenas prácticas relacionadas con el testing, inyección de dependencias y similar y como querían conseguir que llegaran a todo el mundo decidieron que el mejor sitio para ponerlos era el baño. Como la iniciativa tuvo mucho éxito dicidieron publicar esas hojas también en internet incluso en una versión fácil de imprimir en pdf para que cualquiera pueda ponerlas en el baño de su oficina. Y el contenido de muchas de ellas es bastante bueno, como en esta que vemos aquí en la que precisamente trata sobre el naming. Podemos ver un ejemplo con un nombre de test que a pesar de ser mejor que testSum sigue sin dejar muy claro qué está testeando, sabemos que se testea el método isUserLockedOut para login inválido, pero para tener más detalles necesitamos entrar a leer el código. Sin embargo, si llamamos al test isUserLockedOut:lockOutUserAfterThreeInvalidLoginAttemps, aunque es largo queda claramente definido el objetivo de ese test.
Por ello volviendo a nuestro ejemplo de la calculadora yo prefiero usar nombres del estilo de sum_returnsTheAdditionForTwoPositiveNumbers o quizás sum_throwsAnExceptionForNegativeNumbers si por ejemplo quisiéramos que una restricción de nuestro método es que solo suma números positivos.
Ahora que ya tenemos el esqueleto del test, vamos a ver el contenido. En junit existen una gran variedad de métodos que nos permiten hacer comparaciones como assertTrue, assertFalse, assertEqual. En el ejemplo usamos assertEquals para dos dobles con una desviación. Sin embargo los métodos de junit a menudo pueden ser un poco confusos, es difícil recordar qué va primero lo esperado o lo calculado? Por ello existe una librería llamada hamcrest que permite que las comprobaciones sean más semánticas y más legibles. Por eso a partir de la versión 4.4 de junit han decidido añadir el método assertThat y han incluído también