Cómo testear tus modelos con RSpec en Ruby on Rails

Giancarlos Isasi
7 min readJul 6, 2016

--

En este post hablaremos sobre TDD y sus ventajas, del mismo modo mostraremos un ejemplo de como hacer TDD para los modelos en Ruby on Rails haciendo uso de la famosa gema ‘RSpec’ y finalmente explicaré, desde mi punto de vista, porque los tests son importantes.

Muchas veces hemos escuchado sobre el famoso “Test-Driven Development (TDD)” que no es nada más que, primero hacer los tests y correrlos esperando que estos fallen (RED), escribir el código y volver a correr los tests esperando que estos pasen (GREEN) y finalmente refactorizar el código.

La primera vez que escuche sobre TDD pensé:

Escribir tests antes que el código? cómo pruebas algo que aun no has codeado? (ノ ಥ ウಥ )ノ

Luego entendí porque me miraban así cuando olvidaba hacer los tests:

Con todas esas dudas y mas, me sumergí en el oscuro abismo de TDD, ‘Test-first’, etc -[en si existen muchos conceptos y ‘teorías’ respecto al desarrollo guiado por tests, no explicaré todos porque nos tomaría todo el día, noche, mes, año…]- aunque al inicio me costó entender cómo funcionaba, ahora agradezco a Dios, Buda, Alá, Zeus, Mahoma y todos los dioses habidos y por haber ╰( ಠ ω ಠ )╯. Con el TDD pude reemplazar los ‘Clicks’ por ‘Código’, me sorprendió mucho el poder probar/testear interfaces completas de webs a ‘punta de código’.

Ok, entonces dejémonos de parla y vayamos a la acción!! (┛◉Д◉)┛

Actualmente programo en Ruby y trabajo con su famoso framework “Ruby on Rails”.

RoR es un entorno de desarrollo web de código abierto que está optimizado para la satisfacción de los programadores y para la productividad sostenible.

Ruby on Rails también obliga a no repetir partes de código (Don’t repeat yourself) y permite que el desarrollador pueda comenzar su trabajo sin tener que meterse en las tortuosas configuraciones que muchas veces tenemos que hacer en nuestro entorno de trabajo (Convention over configuration).

Ruby on Rails, por defecto, tiene integrada la funcionalidad para los tests. Al crear tu aplicación notarás que esta tendrá una carpeta “test”. Dentro de esta carpeta podrás colocar todas las pruebas que quieras. Casi siempre se tiene una carpeta ‘Models’ en donde colocas los tests para tus modelos, otra llamada ‘Controller’ en donde colocas los tests para los controllers y así; y digo casi siempre porque este tipo de estructura depende del tipo de aplicación así como del tipo de desarrollador -[Por ejemplo para las API’s algunos desarrolladores prefieren crear una carpeta llamada ‘requests’ y dentro de ella colocar los test para los controllers pues consideran que de alguna manera ellos no están testeando los controllers sino las peticiones o ‘requests’]-.

El código de arriba -[por fin algo de código (´⌣`)]- es un ejemplo de como RoR crea por defecto los tests para los modelos. Pero para esta ocasión nosotros usaremos la gema RSpec.

RSpec usa una sintaxis un tanto diferente; puedes revisar la documentación en los links que dejaré al final del post; mientras que la sintaxis por defecto que nos da RoR nos obliga a definir los tests directamente (test “the truth” do…) Rspec nos permite poder agruparlos usando ‘describe’ que describe, valga la redundancia, lo que harán el conjunto de tests-[en RSpec un test es un ‘ejemplo’ y estos son definidos usando ‘it’]-.

En el ejemplo de arriba podemos ver como la sintaxis es mucho más clara y entendible, tenemos un ‘describe ’ que agrupa a 3 ejemplos (tests). Por cierto, si notaron en este (linea 5) y en el anterior ejemplo(linea 4) se define lo que se esta testeando con “:type => controller do”, no es necesario pero es una buena práctica . Veamos un ejemplo sencillo de como testear los modelos junto a sus validaciones.

Primero, esta será la estructura de nuestro modelo que en este caso se llamara: contact.rb y que contiene los campos para firstname, lastname y email

Estos serían nuestros tests para nuestro modelo ‘contact’ usando la gema RSpec. Nótese que el nombre de archivo que contiene los tests tiene el formato de ‘model_spec.rb’ .

Lo primero que hacemos es un ‘describe’ para agrupar todos los ejemplos (tests) pertenecientes al modelo. Dentro de un ‘describe’ también podemos hacer otro ‘describe’ -[podríamos usar uno para agrupar los ejemplos (tests) pertenecientes a algún método de nuestro modelo ‘Contact’ como por ejemplo un def name que nos devuelva el nombre completo de un contacto en especifico]- tenemos 4 ‘it’ o ejemplos, todas enfocadas a probar las validaciones definidas en nuestro modelo contact.rb.

El primer ejemplo (test) es ‘is valid with a firstname, lastname, and email’. Dentro de nuestro modelo tenemos la validación “presence: true” para nuestros campos, lo que hacemos para testear esto es, primero crear un nuevo Contacto (linea 3–6 ) con cualquier dato de ejemplo que deseemos -[existe una gema llamada Faker que nos permite crear y usar estos objetos o datos de prueba de manera mas sencilla]-

Luego especificamos lo que esperamos que suceda con ‘expect’ (linea 7) , le pasamos como parámetro a nuestro objeto contact recién creado y con ‘be_valid’ le decimos que este objeto debería ser válido. Ser válido porque se cumple con el presence: true ლ(╹◡╹ლ).

En el segundo test..

..trataremos de testear que un contact deba tener obligatoriamente un firstname, esto por obvias razones. Lo primero (línea 3) es crear nuestro objeto contact con un firstname nil y lo que esperaremos (linea 5) es que nuestro objeto contact, dentro de su método errors , debería tener incluido (‘include’) el mensaje de ‘can’t be blank’ . Y lo mismo hacemos para los tests restantes, en uno lo hacemos para corroborar que un modelo sea inválido si no tiene un lastname (it “is invalid without a lastname” do) y para el otro, para corroborar que sea inválido si no tiene un email (it “is invalid without a email” do). Entonces podemos decir que de cierta forma creamos el test necesario para nuestro modelo Contact!, We did it!!

RSpec nos permite escribir las pruebas unitarias así como las pruebas de integración.

Para terminar…

…quizás al inicio se te sea complicado o incluso innecesario escribir los tests primero y luego el código, pero de una de las ventajas más grandes es que al final de proyecto no necesitarás utilizar algún depurador o debugger o hacer ‘clicks’ como un crazy-tester en las interfaces. Ademas que TDD agrega valor añadido a las aplicaciones ya que se crean con mucha más calidad. Y no solo esto, si no que también permite detectar algún error que genera el agregar un nuevo componente, modulo o funcionalidad a la aplicación. Algunos dicen que TDD esta muerto, pero no es cierto, creo que solo se esta cambiando el enfoque al que va dirigido.

Y sí, lo sé, quizás te tome mucho mas tiempo desarrollar una aplicación haciendo uso de TDD -[y esa es la principal razón por la que algunos desarrolladores no escriben tests]- pero créeme al final agradecerás haberlo hecho ya que, como lo mencioné anteriormente, la calidad de software sera mayor. Espero que este post le sea de ayuda y le sirva como una pequeña introducción a TDD y a la fabulosa gema RSpec.

Puedes revisar otros post:

Links:

Gracias por leer..! ( ゚,_ゝ゚), si te gustó puedes recomedar el post a tus amigos o compartirlo.

--

--

Giancarlos Isasi

Javascript Developer | Sr Frontend Developer at @crehanacom | Learning nodejs | Ruby/Python fan