No es test de UI todo lo que reluce

El desarrollo de tests está a la orden del día como práctica habitual para asegurar la calidad del software. No solo ingenieros QA, sino también ingenieros de software, tienen como una de sus tareas el añadir tests a sus desarrollos. La idea principal es evitar errores y situaciones regresivas, así como aprovechar las bondades de los sistemas de integración contínua para realizar su ejecución de manera automática.

Bien es sabido que existen múltiples tipos de tests, y cada equipo de desarrollo/QA se puede hacer cargo de determinados tipos. Esto algo a determinar dependiendo de las características y aptitudes que existan dentro del equipo. Siempre me llamó la atención que la línea conceptual que separa determinados tipos de tests es muy fina, y no siempre se distingue bien.

Qué es un test de UI

Los tests de interfaz de usuario (UI):

  • Única y exclusivamente testean la UI.
  • Testean cómo reacciona la UI ante diferentes configuraciones de la lógica subyacente.
  • Testean cómo reacciona la UI ante eventos e usuario atómicos.

Para poder abstraer la UI del resto de la lógica son fundamentales una arquitectura y diseño correcto basado en cualquier patrón testable. Por ello, seguir los principios SOLID es muy importante. No solo para realizar un buen desarrollo, sino también para poder tener una buena testabilidad.

Es frecuente encontrar algo de confusión al respecto, ya que no todo lo que usa la UI para probar es un test de UI. Si estamos probando cualquier tipo de lógica no relacionada con UI usando eventos y asertos de UI, quizá no estamos haciendo algo bien. Puede que el test no este bien enfocado o puede que nuestro código no sea todo lo testable que debería. En este punto tendremos que replantearnos qué y cómo podemos hacer los tests para que sean lo más óptimos hacia nuestras necesidades.  

Qué no es un test de UI

Los test de aceptación (a veces también llamados de plataforma, end-to-end, o incluso finales)  están también muy extendidos para probar escenarios completos. Como tal, usan habitualmente la UI como punto de entrada. Eso implica, que incluso podemos usar los mismos frameworks para desarrollar tests en algunos casos, pero sin olvidar que eso no les convierte en tests de UI. 

Vamos a ver un ejemplo muy sencillo que nos ilustre esta diferencia. Usaremos una de las más conocidas funcionalidades que existen: el login. Para ello, recogemos los datos del formulario por pantalla y existirá una lógica por debajo de la UI que los valida, y a continuación, devuelve el resultado. Qué haría un test de UI ante un escenario de login correcto?

Usaremos en este ejemplo las sintaxis de Espresso y Mockito:

fun testLoginCorrect(){

    `when`(authenticator.checkCredentials(anyString(), anyString())).thenReturn(EXITO)

    //User events to fill UI components
    onView(withId(R.id.loginTextView)).perform(replaceText("username"))
    onView(withId(R.id.passwordTextView)).perform(replaceText("password"))

    //Submit the credentials to the authenticator entity
    onView(withId(R.id.buttonSubmit)).perform(click())

    //Assert the final status
    onView(withId(R.id.statusTextView)).check(matches(withText("Correct Credentials")))

}

y que haría un test de aceptación:

fun testLoginCorrect(){

    //User events to fill UI components
    onView(withId(R.id.loginTextView)).perform(replaceText("username"))
    onView(withId(R.id.passwordTextView)).perform(replaceText("password"))

    //Submit the credentials to the authenticator entity
    onView(withId(R.id.buttonSubmit)).perform(click())

    //Assert the final status
    onView(withId(R.id.statusTextView)).check(matches(withText("Correct Credentials")))

}

casi iguales, ¿verdad?. Pero la realidad es que son tests muy diferentes. En el caso del test de UI, estamos incluyendo una respuesta fake (gracias a Mockito), que nos asegura que la lógica que comprobará las credenciales no esta involucrada en este test. Dicha lógica tendrá sus propios tests, que serán típicamente unitarios y separados por completo de estos y de cualquier otro componente o capa de diseño con la que pudiera estar relacionado. En el caso del test de aceptación, la misma lógica que validará las credenciales en producción estará presente en el test. 

La diferencia, como ya hemos comentado, es el scope de la prueba. La abstracción permite en el primer caso asegurar que los asertos se centran en la UI. Mientras, en el segundo, un fallo en la lógica subyacente haría fallar el test independientemente del comportamiento esperado de la UI. Pero leemos el código y son prácticamente iguales, de ahí que no siempre la distinción sea clara y cristalina.

Por donde empezar

Por citar algunos frameworks útiles a la hora de desarrollar tests de UI para apps móviles: KIF, Earlgrey (iOS), Espresso, Robotium (Android). Si nos interesa un ámbito de aceptación, podemos citar Calabash en el mundo móvil. Conoces alguno de ellos? cual es tu preferido? 

En Solid GEAR trabajamos en diferentes proyectos desarrollando tests de distintos tipos sobre los productos. En el caso de ownCloud, mi compañero David González y yo desarrollamos tests para cubrir las necesidades de la aplicación de Android, tanto unitarios como de UI.

Artículos relacionados:

Deja un comentario

Responsable » Solidgear.
Finalidad » Gestionar los comentarios.
Legitimación » Tu consentimiento.
Destinatarios » Los datos que me facilitas estarán ubicados en los servidores SolidgearGroup dentro de la UE.
Derechos » Podrás ejercer tus derechos, entre otros, a acceder, rectificar, limitar y suprimir tus datos.

Envíando este formulario aceptas la política de privacidad.

¿Necesitas una estimación?

Calcula ahora