Google Play cada vez tiene más y más aplicaciones, lo que a veces lleva a que puedan existir aplicaciones similares a la nuestra. O simplemente que no resulte tan sencillo que los usuarios den con nuestra aplicación.
Para ello, es necesario diferenciar nuestra aplicación del resto. Y no hay mejor forma de diferenciarla que con una buena opinión de los usuarios: consiguiendo un alto nivel de puntuación sobre 5 y número de descargas.
El testeo, la llave hacia la calidad
¿Cómo conseguir esto? Hay un paso vital: el testeo. Testear nuestra aplicación nos llevará a evitar una mala experiencia de uso en determinadas situaciones o dispositivos, dada la variada naturaleza por la que están formados (memoria, procesador, pantalla…). Realizar este testeo de modo manual además puede ser tedioso, por lo que también es interesante profundizar en el concepto de testeo automatizado.
En el caso de Android, todo el testeo lo basaremos en base a la librería Android Testing Support library (ATSL), la cual nos abastece de todo el framework necesario para poder testear la aplicación, incluyendo:
- JUnit4 y un lanzador de tests compatible con los mismos (AndroidJUnitRunner)
- Espresso, para testear la interfaz gráfica
- UI Automator, para la automatización de testeo de la interfaz gráfica
El patrón modelo-vista-controlador y su sencillez para testear
Si bien es cierto es que en el mundo de la programación tenemos una gran variedad de arquitecturas, con sus pros y sus contras, no todas ellas son fácilmente testeables, permitiendo estructurar de una forma segura el código. Cuanto más separable sean las partes de una app, más testeable será la arquitectura que utiliza. De esta forma, será más sencillo de mantener y testear de forma individual.
Un buen ejemplo es el patrón Modelo-Vista-Presentador es una de las arquitecturas más sencilla para poder testear una aplicación. La explicación es bien sencilla, pues todo el código está estructurado en 3 grandes capas:
- Modelo: Esta capa gestiona los datos de forma interna y los almacena. Son las clases que solemos denominar clases de lógica de negocio.
- Vista: Se encarga de mostrar los datos, pero sólo de mostrar los datos. En este grupo entrarían nuestros Fragmentos y Vistas.
- Presentador: Este elemento se sitúa entre el modelo y la vista permitiendo coordinar la interfaz gráfica con los datos, para mantenerlo todo sincronizado. Además, se hará cargo de la interacción del usuario. Aquí entrarían en juego todos los listeners, entre otras clases.
Si deseas ver un ejemplo muy fácil de comprender, explicado a paso, de una aplicación (que es una app de notas) que implementa la arquitectura MVP, debes visitar el siguiente enlace:
Los tests unitarios: JUnit4 y Mockito
Desde la llegada de Android Studio, el testeo cobró mucha importancia para Android. De ahí que la estructura gradle de los proyectos contemplara ya estas necesidades. Por ello, en Android Studio podemos tener en el mismo proyecto, pero en diferentes ramas el código de compilación de nuestra app y por otro lado el código para testear.
¿Código para testear? Sí. Se trata de código que su única misión es poner a prueba nuestro código para saber que en todos los casos está ocurriendo lo que esperamos. Pero para que éste tenga sentido, se simplifica al máximo y se hacen tests muy específicos que testean cosas muy simples (es mejor tener 1000 tests para nuestra aplicación que 10 muy grandes). De ahí el nombre de test unitario.
Para ello, se utiliza JUnit4, donde podemos definir los métodos por clases y así ejecutar cada uno de ellos por separado o por grupos relacionados. Para ello, utilizaremos una serie de etiquetas, las cuales nos permitirán seguir los pasos necesarios para cualquier test unitario:
- Preparar el contexto: Esta fase es clave para un buen testeo, pues se trata de preparar todas y cada una de las variables que pueden condicionar nuestro testeo. Por ejemplo, si vamos a testear que un trozo de nuestro código oculta un botón de la interfaz en determinadas condiciones, primero deberemos estar seguros de que el botón está visible, así como poner las condiciones que harán que oculte al llamar a nuestro código. En este punto puede interesarnos utilizar las etiquetas @Before y @BeforeClass
- Ejecutar nuestro código: Esta parte es la más sencilla, que radica en, una vez preparado el contexto, llamar a nuestro código productivo.
- Comprobar los resultados: Tras ejecutar nuestro código, basta con comprobar lo que queríamos comprobar. Para ello tendremos clases específicas que nos permitirán comprobar cualquier cosa, como la clase Assert.
- Restablecer los valores: Por último, y no menos importante, un test no debe dejar modificaciones en el estado de nuestra aplicación, por lo que hay que deshacer los cambios que el test pudiera haber realizado. Para ello, se utilizan las etiquetas @After y @AfterClass
Nuestro proyecto además entenderá que ese código es un test unitario cuando tenga la etiqueta @Test.
A partir de ahí, debemos saber implementar tests lo más independientes posibles. Para ello, se utiliza la librería Mockito, la cual nos permite simular lo que deseemos, sin necesidad de llevarlo a cabo. Es decir, si vamos a testear un código que delega en otro, podríamos testear que simplemente se ha delegado en el otro, no que el código en el que se delegó hace su función bien (lo que testearíamos aparte). De esta forma, estamos aislando totalmente el testeo y separando toda dependencia.
Por ello, si queremos tener una buena estructura de testeo, debemos comprender Mockito y aprender a sacarle todo el partido posible. Si quieres ver un buen ejemplo, paso a paso, no dudes en visitar el ejemplo que Google nos proporciona:
Testeando interfaces con Espresso
Testear la lógica de negocio puede ser quizá la parte sobre la que más control tengamos. Testear toda la interfaz puede ser más complejo, dado que necesitamos del contexto del dispositivo (o emulador). Para ello, Google pone a nuestra disposición Espresso, una API que nos permite simular interacciones de usuario. De esta forma, podremos automatizar interacciones del usuario, para poder entonces testear sus resultados.
Como podéis ver en el ejemplo anterior, los tests son muy similares, pero en este caso podríamos estar simulando por ejemplo que tocamos un componente de la interfaz con el dedo, y después comprobando que otro componente es mostrado.
¿Os imagináis cuanta cantidad de testeo podemos automatizar? Sí, es posible.
Code Coverage: la prueba empírica de nuestro testeo
Una vez conocemos esto, podemos pensar en lo siguiente: ¿cómo sabemos qué parte de nuestro código está cubierta por nuestros tests y cuál no? Conforme una app es más grande, esto se vuelve más y más tedioso.
Por ello, disponemos de herramientas llamadas Code Coverage, las cuales nos permiten comprobar, clase por clase, cuál es el porcentaje de código cubierto, así como qué código está cubierto y cuál no.
Android Studio permite generar estos informes a partir de nuestros tests, por lo que poder identificar las posibles partes donde tendremos bugs ya no es tan tediosa como esperábamos, ¿no?
Continuous Integration: tests y coverage, pero actualizados
Ya tenemos tests, y tenemos porcentajes sobre el código cubierto por los tests y el que no. ¿Qué nos falta? Muy sencillo: que toda esa información esté actualizada. Para ello, se introduce el concepto de servidor Continuous Integration, el cual se dedica a, según como le indiquemos, coger el código (cada x tiempo o cada vez que haya cambios si trabajamos en un servidor con control de versiones) y compilar el código y lanzar todos y cada uno de los tests. Algunos ejemplos de estos servidores son Jenkins o Team City.
De esta forma, si tenemos un servidor encargado de esta tarea, no necesitaríamos perder tiempo en nuestra máquina local para los tests. Incluso este servidor podría tener conectados dispositivos reales sobre los que se lanzan los tests.
Una vez los termine, mediante una web, podríamos consultar todos los resultados en cuanto a tests que han fallado y code coverage. Con esto, que nuestra aplicación tenga calidad pasa a ser algo más empírico, donde podemos basarnos en estas estadísticas. Por tanto, el que no quiere calidad, es porque no quiere.
Android Testing Codelab
Para finalizar, y para daros más información que consultar, os recomendamos ver el código de ejemplo sobre testeo que nos pone a nuestra disposición Google. Basta que sigáis este CodeLab de Google, del que anteriormente ya os hemos puesto algún enlace:
En él, podréis encontrar, en inglés, muchos de estos conceptos de los que hablamos, así como código de ejemplo sobre el que poder ir haciendo pruebas en nuestras máquinas, ya que ¡los desarrolladores no descansamos ni en Semana Santa!