Spek! ¿Qué quieren decir estas pruebas?

Yamil Medina
Droid LATAM
Published in
5 min readDec 6, 2019

Comencemos hablando de las pruebas unitarias y las motivaciones para que éstas existan. Si bien las más nombradas y repetidas, cada vez que hablamos de estos temas son: “Asegurar calidad”, “Tolerancia a fallos”, “Facilita los cambios”, hay uno no menor que a veces pasamos por alto, o sub-entendemos, hablo sobre la documentación que provee a un sistema.

Alguna vez escuché de un colega -quién había hecho cambios recientes de lenguajes de programación, específicamente de Python para Swift y de contextos de negocio en los últimos meses- que dijo:

“Lo primero que hago para entender el negocio del proyecto, la tecnología involucrada y la arquitectura…es mirar las pruebas”

Y resulta que esto cada vez tiene más sentido para mí hoy, estoy cambiando de proyecto y sin minimizar lo que un buen proceso de onboarding debe cubrir en relación al entendimiento del contexto/negocio del proyecto. Mirar pruebas bien documentadas siempre se agradece.

Entonces acá, nos vamos a enfocar en cómo podemos hacer pruebas que documenten mejor la intención de un sistema, sus partes y qué aprendizajes podemos sacar de otros frameworks.

Nuestro objetivo:

“Escribir pruebas en la JVM que documenten bien nuestra aplicación y que de paso nos den un feedback comprensible de las fallas”.

Opción 1: Sólo con JUnit

El estándar por defecto de cualquier proyecto Java (hoy en día tenemos que incluir Kotlin) es usar JUnit como motor principal de pruebas, donde lamentablemente no tenemos muchas herramientas para lograr nuestro objetivo (☝️👀). Veamos cómo con algunas pequeñas mejoras podemos describir mejor qué es lo que hace cada prueba. Vamos con algunos ejemplos:

Tomemos la siguiente prueba base

1.1. Nombre de las pruebas

Agregando una pequeña mejora: Un nombre de prueba más específico, que nos diga claramente qué es lo que esta unidad está haciendo:

@Test
public void addingTwoNumbersReturnsItsSum() {
//given...
//when...
//then...
}

1.2. Mejores verificaciones “asserts”

Un assert más cercano al lenguaje natural “legible para humanos” con la ayuda de “hamcrest”. Comparando el código de arriba y el siguiente, ya podemos notar una mejora, logramos un lenguaje más cercano al negocio.

import static org.hamcrest.CoreMatchers.is;@Test
public void addingTwoNumbersReturnsItsSum() {
//given...
//when...
//then
assertThat(total, is(3));
}

Opción 2: La manera Kotlin

Kotlin, ya sabemos que ha venido a revolucionar muchos aspectos de cómo escribimos código en la JVM, similar a lo que para algunos más viejitos como yo, groovy, ya intentó:

:oldparrot:

Kotlin, lo ha llevado más allá, en parte por el apoyo de Google + Android, que ha impulsado la adopción a niveles no presupuestados. Asumiendo las mejoras anteriores que hicimos, vamos a continuar desde ahí, pero ahora enfocándonos sólo en lo que Kotlin nos provee.

2.1. El truco de las comillas `Backticks Hack`

Kotlin, nos da una manera sencilla de escribir pruebas más legibles, según su coding conventions:

… In tests (and only in tests), it’s acceptable to use method names with spaces enclosed in backticks …

Entonces, podemos expresar nuestro test de la siguiente manera:

@Test
fun `Adding TWO numbers in a Calculator should return their total`() {
//given...
//when...
//then...
}

Mucho más claro el propósito de la prueba, ¿no? Quizás es debatible, pero sí puedo asegurar que a la hora de leer el resultado de las pruebas en un log de 1000 pruebas, será mucho más sencillo, inclusive a la hora de leer como documentación sobre nuestra calculadora.

Opción 3: Introduciendo Specs y Spek

Seguramente varios ya están familiarizados con “specifications test”, que nos permite probar nuestro código y por sus características servir también de documentación para el resto de las personas (no hablo de los demonios internos del desarrollador 🙃). Hablo de las futuras personas desarrolladoras o el mismo negocio.

Esta forma de escribir pruebas ha sido popularizada por frameworks como RSpec, Jasmine y otros más dependiendo del lenguaje que estemos hablando. Lo importante para nuestro objetivo (☝️👀) es que para Kotlin existe un framework complementario de pruebas llamado Spek, desarrollado por el mismo JetBrains. Vamos a mirar su sintaxis y cómo nos ayuda con el objetivo planteado inicialmente:

import org.spekframework.spek2.style.specification.describe
import org.spekframework.spek2.Spek
object CalculatorSpec: Spek({
describe("A calculator") {
val calculator by memoized { Calculator() }
context("addition") {
it("returns the sum of its arguments") {
assertThat(calculator.sum(1, 2), is(3))
}
}
}
})

Context/Describe: Damos un grupo o contexto de ejecución de la prueba, equivalente a una Suite, nos sirve para nuestro caso agrupar pruebas de la suma de nuestra calculadora.

It: Realiza la validación específica y atómica de la prueba, que en este caso sería el resultado de sumar uno y dos es igual a tres. En términos simples nuestra especificación.

A la hora de mirar los conceptos anteriormente presentados, podemos “imaginar” sobre cómo agregaríamos nuevas funcionalidades a nuestra calculadora y de paso teniendo en cuenta esta dualidad; documentación-prueba, hagamos el siguiente ejercicio.

Queremos incluir a nuestra calculadora la posibilidad de dividir entonces nos damos cuenta que la descripción de esta nueva feature y sus distintas casuísticas, las describimos (describe) en la prueba dentro del mismo contexto (context).

object CalculatorSpec: Spek({
context("A calculator") {
val calculator by memoized { Calculator() }
describe("addition") { /*..*/} describe("division") {
it("returns the division of its arguments") {
assertThat(calculator.divide(10, 2), is(5))
}
it("throws an exception when divisor is zero") {
assertFailsWith(ArithmeticException::class) {
calculator.divide(1, 0)
}
}
}

}
})

A continuación el detalle de las configuraciones para agregar Spek2 a tu proyecto android:

app: build.gradle
root: build.gradle

Para cerrar, más allá de los patrones y librerías que utilicemos al escribir pruebas en nuestras aplicaciones, en este ejemplo es Spek, mañana puede ser otro, lo importante será pensar en el futuro “yo” que tomará algún día el mantenimiento de nuestra aplicación, podría ser una persona sin contexto del proyecto o jugando con las palabras, podríamos ser nosotros mismos años después revisitando nuestra aplicación.

Referencias:

--

--

Yamil Medina
Droid LATAM

Software Engineer / Android Developer / JVM ❤ / Cycling enthusiast