Académique Documents
Professionnel Documents
Culture Documents
del desarrollo, aun es más difícil encontrar desarrolladores que escriban los test con al
menos el mismo cariño que escriben el resto.
Los test es código igualmente y tenemos el mismo deber de cuidarlo porque tendremos que
mantenerlos a lo largo del tiempo.
Existen multitud de beneficios que se producen al escribir test legibles, cito algunos:
Conclusiones
El código de los test es tan importante o más que el resto. Por lo tanto es necesario cuidarlo,
hacerlo limpio y legible porque nos puede dar muchos beneficios
De lo simple a lo complejo
“SUELO TENER UNA NORMA QUE ME FUNCIONA BASTANTE BIEN QUE ES
IR DE LO SIMPLE A LO COMPLEJO.”
No suelo empezar a crear tests utilizando muchos patrones como los que vamos a ver en
este artículo, intento empezar por la opción más simple.
A medida que voy creando tests y voy identificando código duplicado, acoplado o que los
test se empiezan a leer mal es cuando empiezo a optimizar el código a base de
refactorizaciones.
Opción simple
Como ya escribí en el artículo Escribiendo test legibles, me gusta que los test se mantengan
pequeños porque a medida que son mas grandes se empiezan a leer peor y son más difíciles
de mantener.
Si el objeto a probar (SUT) es una entidad de dominio pequeña, donde el constructor para
crear instancias no tiene muchos parámetros o donde no tenemos que interactuar con el
objeto una vez creado para situarlo en un estado en particular, es bastante sencillo mantener
esta simplicidad.
Object mother
No todos los test son el ejemplo sencillo, existen situaciones donde es necesario escribir
código adicional para configurar el fixture o contexto de la prueba, por ejemplo:
@Test
El primer problema que suele aparecer cuando existen colaboradores es que se pierde
legibilidad en el test, porque la forma en la que se crea el colaborador es indiferente para el
test del objeto a probar (SUT).
Adicionalmente aparece otro problema, a medida que se crean más tests vamos a tener que
crear el colaborador muchas veces, esto provoca un uso masivo de constructores o métodos
de factoría del propio colaborador.
Cuando creamos manualmente colaboradores nuestros test se vuelven frágiles, al igual que
cuando utilizamos frameworks directamente en los test.
Cuando cambian los constructores o métodos de factoría tenemos que ir por todos esos
sitios actualizando la creación de objetos para adaptarlo.
Una forma de minimizar este problema es utilizar el patrón ObjectMother.
Normalmente utilizo este patrón cuando de un objeto existe un juego de combinaciones
concretas que suelo utilizar en gran número de tests.
Otro tipo de objetos con lo que suele venir muy bien utilizar el patrón Object Mother es con
los típicos maestros.
Refactorizando el ejemplo anterior nos quedaría así:
return Currency.getInstance("EUR");
return Currency.getInstance("USD");
}
@Test
Patrón builder
Pero hay situaciones donde el patrón Object Mother se queda corto:
Si hay varios objetos a crear, la legibilidad del test aunque mejora, todavía hay
configuración del fixture que hace que la legibilidad del test este lejos de ser la
mejor.
Si necesitamos muchos escenarios distintos de un mismo objeto, podríamos utilizar
el patrón Object Mother pero tendríamos que crearnos un método por cada
escenario dentro del mismo objeto. Esto provocaría tener un objeto demasiado
grande, muy acoplado a los tests y difícil de mantener.
Hay valores dentro de la creación del objeto que son irrelevantes para el test y
pueden asignarse unos valores por defecto cualquiera
Cuando se produce alguna de estas situaciones es cuando suelo utilizar el Patrón Builder.
Este patrón te permite tener mucha más flexibilidad para crear el fixture y el objeto que
usamos esta menos acoplado y mejora la legibilidad porque estamos ocultando como se
crea el objeto realmente.
El Patrón Builder se suele implementar con api fluida y mejora la legibilidad donde se esta
utilizando.
this.amount = amount;
return this;
this.currency = currency;
return this;
@Test
public void return_display_name_as_amount_concat_with_currency_symbol() {
.withAmount("100.00")
.withCurrency(Currencies.EURO())
.build();
Creation Method
Es posible que si para configurar el fixture hay que crear más objetos que en los casos
anteriores, van a seguir apareciendo los mismos problemas que teníamos antes aunque en
menor medida:
legibilidad del test, configuración de colaboradores irrelevante para el test actual , etc..
Vamos a ver un caso donde combinamos un objeto producto con los que ya teníamos:
this.title = title;
return this;
}
this.amount = amount;
return this;
this.currency = currency;
return this;
.withAmount(amount)
.withCurrency(Currencies.EURO())
.build();
product.ChangePrice(price);
return product;
}
}
@Test
.withAmount("100.00")
.withCurrency(Currencies.EURO())
.build();
product.markOnSale();
assertThat(product.isOnSale(), is(true));
En este test la cantidad y la moneda del precio es irrelevante para el test, se esta perdiendo
legibilidad.
En este caso suelo utilizar un método de creación dentro de la propia clase de test que libere
completamente al método del test de conocer la configuración del fixture.
Este método de creación lo suelo crear con el prefijo given.
@Test
public void is_on_sale_if_its_not_free_and_is_marked_as_on_sale() throws Fre
eProductOnSaleException {
product.markOnSale();
assertThat(product.isOnSale(), is(true));
.withAmount("100.00")
.withCurrency(Currencies.EURO())
.build();
Conclusiones
En este artículo hemos visto los patrones que suelo utilizar para optimizar el código de los
test cuando empiezo a identificar código duplicado, demasiado uso de constructores de las
entidades de dominio o si se empieza a perder legibilidad en los test.
No hay que ponerse la venda antes que la herida y solo cuando empezamos a ver problemas
en el código es cuando debemos empezar a optimizar el código.
http://xurxodev.com/como-utilizo-patrones-de-diseno-en-test-unitarios/