Testing en Ruby: Minitest vs RSpec

Lucas Hourquebie
Nov 2, 2018 · 6 min read

El testing es una parte imprescindible en el proceso de desarrollo de software y nos permite validar el funcionamiento de un sistema conforme a sus requerimientos y reglas de negocio, constituyendo un paso necesario para asegurar la calidad de los sistemas.

Por lo tanto, el testing sirve, por un lado, para garantizar el correcto funcionamiento de los sistemas que desarrollamos, y por otro para validar que los cambios venideros que pueden surgir con el paso del tiempo no generen efectos secundarios tales como bugs o flujos de funcionamiento incorrecto.

Casi como una ley natural, los sistemas informáticos evolucionan y se adaptan constantemente a nuevos cambios.

Más allá de lo dicho, el testing también es vital para documentar el funcionamiento del software. Partiendo de la base de que escribimos tests para validar los requerimientos de un sistema, sus incumbencias, limitaciones y reglas de negocios, podemos concluir en que también constituyen un documento que indica lo que un sistema puede y debe hacer, así como aquello que no.

Todo lenguaje de programación está dotado de diferentes herramientas para testear aplicaciones, y Ruby no escapa de esa realidad: existen diversos frameworks de testing ampliamente utilizados, entre los que destacan RSpec y Minitest.

Por un lado, RSpec es el framework de testing más utilizado y aclamado por la comunidad de desarrolladores Ruby, mientras que Minitest es la herramienta de testing de facto de Ruby on Rails, uno de los frameworks de desarrollo web más populares de la actualidad.

En Unagi utilizamos ambos frameworks, por lo que vamos a enumerar sus características basadas en nuestras experiencias y, después, te dejamos como tarea elegir cuál de los dos te convence más.

Minitest

Muchos de nuestros sistemas están construidos en Ruby on Rails. Por lo tanto, inicialmente, tomamos la decisión de utilizar la herramienta que viene por defecto. Minitest es muy simple de utilizar, tiene una sintaxis sencilla y es de rápida implementación con tests de baja a mediana complejidad.

Su utilización consiste básicamente en definir clases que se encarguen de testear a otra clase Ruby, o bien a una integración de ellas, dependiendo del tipo de test que se quiere realizar. Cada clase se compone básicamente de tres partes:

En el siguiente ejemplo podemos observar el test de una clase que maneja la autenticación de un usuario:

class ApiLoginManager < Minitest::Test
setup do
@user = FactoryBot.create(:user)
end
test 'should update user auth_token on successful login' do
assert_changes -> { @user.reload.auth_token} do
response = ApiLoginManager
.new(email: @user.email, password: 'supersecret')
.call
end
end
test 'should return the auth_token on successful login' do
response = ApiLoginManager
.new(email: @user.email, password: 'supersecret')
.call
assert_equal response, @user.reload.auth_token
end
test 'should return EMPTY_EMAIL error when no email is provided' do
service = ApiLoginManager.new(password: 'supersecret')
refute service.call
assert_equal ApiLoginManager::EMPTY_EMAIL, service.error
end
test 'should return EMPTY_PASSWORD error when no password is provided' do
service = ApiLoginManager.new(email: @user.email)
refute service.call
assert_equal ApiLoginManager::EMPTY_PASSWORD, service.error
end
test 'should return USER_NOT_FOUND error when email is incorrect' do
service = ApiLoginManager.new(
email: 'incorrect.email@mail.com',
password: 'supersecret'
)
refute service.call
assert_equal ApiLoginManager::USER_NOT_FOUND, service.error
end
test 'should return USER_NOT_FOUND error when password is incorrect' do
service = ApiLoginManager.new(
email: @user.email,
password: 'incorrect_password'
)
refute service.call
assert_equal ApiLoginManager::USER_NOT_FOUND, service.error
end
end

Cada vez que definimos un bloque test validamos algún requerimiento o funcionalidad, y lo hacemos mediante assertions (o refutations), los cuales validan un resultado en particular, de forma tal de que si las condiciones no se cumple el test falla. Podemos definir varios en cada test y la falla de uno hace fallar al test completo. Existen numerosos tipos de assertions/refutations y pueden encontrarse en este enlace.

RSpec

Últimamente hemos estado cambiando nuestras herramientas de testing y encontramos en RSpec un gran aliado, con una integración perfecta con Ruby on Rails, potenciado por la ayuda de herramientas de las que hablaremos en otra publicación: FactoryBot, Shoulda Matchers y Faker.

RSpec es, a juzgar por las gemas y proyectos que hemos visto, el framework preferido por los desarrolladores Ruby. Es una herramienta muy robusta y preparada para testear cualquier solución que le haga frente.

RSpec es uno de los frameworks de testing más utilizados en la comunidad Ruby.

La estructura de los tests escritos con RSpec es más flexible que la de Minitest, y permite utilizar diferentes descripciones y contextos para clarificar las incumbencias de aquello que se está testeando. A continuación podemos observar un ejemplo utilizando la misma clase que se usó en el ejemplo de Minitest:

RSpec.describe ApiLoginManager do
let(:user) { FactoryBot.create(:user) }

describe 'Successful login' do
subject do
ApiLoginManager.new(email: user.email, password: 'supersecret').call
end
it 'should update user auth_token' do
expect { subject }.to change { user.reload.auth_token }
end
it 'should return the auth_token' do
auth_token = subject
expect(auth_token).to eq(user.reload.auth_token)
end
end
describe 'Failed login' do
context 'when no email is provided' do
it 'should return EMPTY_EMAIL error' do
service = ApiLoginManager.new(password: 'supersecret')
expect(service.call).to be false
expect(service.error).to eq(ApiLoginManager::EMPTY_EMAIL)
end
end
context 'when no password is provided' do
it 'return EMPTY_PASSWORD error' do
service = ApiLoginManager.new(email: user.email)
expect(service.call).to be false
expect(service.error).to eq(ApiLoginManager::EMPTY_PASSWORD)
end
end
context 'when the email is incorrect' do
it 'should return USER_NOT_FOUND error' do
service = ApiLoginManager.new(email: 'a@mail.com', password: 'test')
expect(service.call).to be false
expect(service.error).to eq(ApiLoginManager::USER_NOT_FOUND)
end
end
context 'when the password is incorrect' do
it 'should return WRONG_PASSWORD error' do
service = ApiLoginManager.new(email: user.email, password: 'test')
expect(service.call).to be false
expect(service.error).to eq(ApiLoginManager::WRONG_PASSWORD)
end
end
end
end

En el ejemplo se pueden observar varios elementos propios de RSpec:

Creemos que el testing es un proceso necesario, y es por eso que en Unagi forma parte del ciclo regular del desarrollo de toda aplicación. Entendemos que es de vital importancia elegir buenas herramientas de testing que ayuden a mejorar la calidad de las soluciones que desarrollamos. Es por ese motivo que actualmente utilizamos RSpec ya que, en nuestra opinión y basado en nuestras experiencias, consideramos algunos puntos positivos que respaldan la decisión:


Y vos, ¿qué framework de testing utilizás para tus aplicaciones Ruby/Ruby on Rails? Dejanos tu comentario y algunos 👏 si te gustó el artículo.

Unagi (unagi.com.ar) es una empresa de software enfocada en el desarrollo de soluciones web que ayuden a nuestros clientes a mejorar lo que ya hacen bien. Nuestro equipo está formado por un grupo de ingenieros y licenciados con más de 10 años de experiencia acumulada. Estamos abiertos a nuevas experiencias, y nos encantan los desafíos. Somos felices haciendo lo que hacemos.

unagi

Desarrollos de software a medida para clientes felices

Thanks to Nicolás Galdámez and Gonzalo Galdámez

Lucas Hourquebie

Written by

['Ingeniero en Computación', 'Software developer', 'Pincharrata', 'Amante de cómics DC y cine de ciencia ficción'].join(', ')

unagi

unagi

Desarrollos de software a medida para clientes felices

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade