Construyendo nuestra fábrica de documentos de prueba

9/34

Lectura

Construyendo nuestra fábrica de documentos de prueba

Objetivo

Poder tener todas nuestra fábricas dinámicas de información completamente definidas para empezar a ejecutar la creación de todas las pruebas de nuestro sistema, en esta clase, usaremos FactoryBot y Faker, gemas que habíamos agregado en anteriores clases.

Cada fábrica tendrá la capacidad de generar registros de base de datos de forma automatizada y configurable, para que no tengamos la necesidad de crearlos a mano, esto involucra incluso registros que están relacionados con otros registros por relaciones de base de datos u otros.

Fábrica de Categorías

Para empezar a crear nuestra fábrica, podemos usar el siguiente generador en la raíz del proyecto

$ rails g factory_bot:model category

Este comando generará un archivo de nombre spec/factories/categories.rb en este colocaremos el siguiente contenido

# spec/factories/categories.rb
FactoryBot.define do
factory :category do
sequence(:name) { |n| "Categoria #{n}" }
description { Faker::Lorem.sentence }
end
end

Lo que estamos haciendo en esta fábrica es automatizar la creación de una categoría con los campos name y description mientras en el name estamos usando un sistema de secuenciación de base de datos propio del FactoryBot para evitar que se creen dos categorías con el mismo nombre, en el campo de descripción estamos usando Faker para generar un texto de tipo Lorem Ipsum de forma aleatoria

Fábrica de Usuarios

Usemos el generador para crear la fábrica de usuario

$ rails g factory_bot:model user

Cambiemos el contenido completo del archivo creado por el generador de nombre spec/factories/users.rb

# spec/factories/users.rb
FactoryBot.define do
factory :user do
sequence(:email) { |n| "person#{n}@example.com" }
password { '123456' }
end
end

De igual forma, en la fábrica del usuario estamos usando el sistema de secuenciación del FactoryBot, y también estamos definiendo una contraseña estática con valor 123456

Fábrica de Participantes

Usemos el generador para la fábrica de participantes

$ rails g factory_bot:model participant

Cambiemos el contenido completo del archivo creado por el generador de nombre spec/factories/participants.rb

# spec/factories/participants.rb
FactoryBot.define do
factory :participant do
association :user
trait :responsible do
role { Participant::ROLES[:responsible] }

end
  
trait :follower do
role { Participant::ROLES[:follower] }

end

after(:build) do |participant, _|
participant.user.save

end
end
end

En esta fábrica hemos añadido tres elementos importantes, el sistema de asociación, el sistema de rasgos (traits) y el sistema de callbacks.

Con la definición del método association FactoryBot de forma automática buscará la fábrica de Usuarios para construir el registro de usuario y asociarlo al registro de participante.

Con los rasgos, podemos de forma semántica definir al momento de invocar la fábrica si queremos que el participante tenga una condición específica, en este caso, que su rol sea responsable o seguidor.

Finalmente, con el sistema de callbacks, podemos ejecutar una o varias operaciones cuando el proceso de creación o construcción empiece o termine, en nuestro ejemplo, ejecutaremos el proceso participant.user.save cuando el registro participant termine de construirse asegurando que el registro de usuario si sea persistido.

Fábrica de Tareas

Usemos el generador para la fábrica de tareas

$ rails g factory_bot:model task

Cambiemos el contenido completo del archivo creado por el generador de nombre spec/factories/tasks.rb

# spec/factories/tasks.rb
FactoryBot.define do
factory :task do
sequence(:name) { |n| "Tarea #{n}" }
sequence(:description) { |n| "Descripcion #{n}" }
due_date { Date.today + 15.days }
category
association :owner, factory: :user
  

factory :task_with_participants do
transient do
participants_count { 5 }

end

after(:build) do |task, evaluator|
task.participating_users = build_list(
:participant,
evaluator.participants_count,
task: task,
role: 1
)

task.category.save
task.owner.save

end

end

end

end

A pesar de que parezca complejo, en esta fábrica hemos combinado todos los elementos vistos en las anteriores fábricas y hemos añadido dos conceptos nuevos, el de asociación implícita con la llamada simple al método category y el concepto de fábrica anidada.

La asociación implícita a través del método category simplemente hace lo mismo que la asociación de usuario en la fábrica de participantes, está creando un registro de categoría de forma automática cuando la tarea se está creando. Por otro lado, hay una declaración explícita de la fábrica de usuario en la relación owner, la cual se comporta de igual forma que una asociación normal pero definiendo que la fábrica a usar será :user

La fábrica anidada, nos está dando la flexibilidad de complementar los elementos de la fábrica de tareas principal, dotandonos de la capacidad de crear una tarea con participantes, e incluso poder definir el número de participantes en la tarea construida a través del método transient y la declaración de la variable participants_count que más adelante será accedida en el cuerpo de callback desde un elemento de habilitación de transferencia de datos llamado evaluator

Internamente, en el cuerpo del callback, estamos usando un método de FactoryBot llamado build_list que nos permitirá en un sólo comando crear una lista de registros con una fábrica definida, al final de esta ejecución simplemente estamos persistiendo las asociaciones generadas para el creador de la tarea y la categoría.

Probando nuestras fábricas

La mejor manera de probar nuestras fábricas es con la creación de una prueba automatizada para nuestro proyecto, así que creemos una prueba sencilla para nuestro modelo task, usando el generador de Rails

$ rails g rspec:model task

El contenido del archivo creado spec/models/task_spec.rb debemos cambiarlo por el siguiente

# spec/models/task_spec.rb
require 'rails_helper'
 

RSpec.describe Task, type: :model do
describe '#save' do
let(:participants_count) { 4 }
subject(:task) { build(:task_with_participants, participants_count: participants_count) }
 
it 'is persisted' do
expect(task.save).to eq true
end

context 'after save' do
before(:each) { task.save }

it 'has all associated participants' do
expect(task.participating_users.count).to eq participants_count
expect(Participant.count).to eq participants_count

end

end

end

end

En las siguientes clases, explicaremos a profundidad el flujo y la construcción de nuestras pruebas, haremos más de 30 pruebas al final de nuestro curso, así que no detallaré todos los procesos del contenido de este archivo, sin embargo, lo que estamos haciendo allí, es definir en el cuerpo de la prueba la construcción de una nueva tarea con 4 participantes, y estamos comprobando dos cosas: que esta construcción luego pueda ser persistida y que después de ser persistida el número de participantes persistidos si sea el número que inicialmente he definido, es decir 4.

Para ejecutar las pruebas, debemos ir a la consola de comandos, y en la raíz del proyecto ejecutar lo siguiente

$ rspec

Deberás ver el siguiente resultado como salida del comando

Task
#save
is persisted
after save
has all associated participants

Finished in 0.2038 seconds (files took 0.77674 seconds to load)

2 examples, 0 failures

Aportes 4

Preguntas 0

Ordenar por:

Los aportes, preguntas y respuestas son vitales para aprender en comunidad. Regístrate o inicia sesión para participar.

si les da este error:

An error occurred in a `before(:suite)` hook.
Failure/Error: DatabaseCleaner.orm = 'mongoid'

NoMethodError:
  undefined method `orm=' for DatabaseCleaner:Module
# ./spec/rails_helper.rb:56:in `block (2 levels) in <top (required)>'

es por que el metodo '.ORM = ’ esta deprecated osea la nueva version de DatabaseCleaner no lo utiliza (no se con que lo sustituye).
Yo degrade la version en el gemfile
gem ‘database_cleaner’, ‘~> 1.99’ y recuerden hacer bundle install

El código es muy feo de leer sin la indentación. -_-

Al utilizar faker en el modelo category, tuve que requerirlo, ya que no me pasaba las pruebas.
Agregue un require ‘faker’ al inicio del archivo, lo comento por si a alguien mas no le pasan las pruebas.

Al correr el test del ejemplo obtuve los siguientes dos errores:

rspec ./spec/models/task_spec.rb:10 # Task#save is persisted
rspec ./spec/models/task_spec.rb:16 # Task#save after save has all associated participants

la solucion fue agregar en el rails_helper las siguientes dos lineas de codigo:

config.include Devise::TestHelpers, type: :controller
config.include Devise::TestHelpers, type: :view

Fuente de la solucion está en la tercera respuesta del siguiente post de stackoverflow:

[](https://stackoverflow.com/questions/27284657/undefined-method-env-for-nilnilclass-in-setup-controller-for-warden-error)