¿Cuál es la diferencia entre let
y un before
bloque en RSpec?
¿Y cuándo usar cada uno?
¿Cuál será un buen enfoque (antes o antes) en el siguiente ejemplo?
let(:user) { User.make !}
let(:account) {user.account.make!}
before(:each) do
@user = User.make!
@account = @user.account.make!
end
Yo estudié esto publicación de stackoverflow
Pero, ¿es bueno definir let para cosas de asociación como las anteriores?
ruby-on-rails
unit-testing
rspec
kriysna
fuente
fuente
Respuestas:
La gente parece haber explicado algunas de las formas básicas en las que se diferencian, pero no
before(:all)
y no explican exactamente por qué deberían usarse.Creo que las variables de instancia no tienen lugar en la gran mayoría de las especificaciones, en parte debido a las razones mencionadas en esta respuesta , por lo que no las mencionaré como una opción aquí.
dejar bloques
Código dentro de un
let
bloque solo se ejecuta cuando se hace referencia, la carga diferida significa que el orden de estos bloques es irrelevante. Esto le brinda una gran cantidad de energía para reducir la configuración repetida a través de sus especificaciones.Un ejemplo (extremadamente pequeño y artificial) de esto es:
Puede ver que
has_moustache
se define de manera diferente en cada caso, pero no es necesario repetir lasubject
definición. Algo importante a tener en cuenta es quelet
se utilizará el último bloque definido en el contexto actual. Esto es bueno para establecer un valor predeterminado que se utilizará para la mayoría de las especificaciones, que se pueden sobrescribir si es necesario.Por ejemplo, verificar el valor de retorno de
calculate_awesome
si se pasa unperson
modelo con eltop_hat
valor verdadero, pero sin bigote sería:Otra cosa a tener en cuenta sobre los bloques let, no deben usarse si está buscando algo que se ha guardado en la base de datos (es decir
Library.find_awesome_people(search_criteria)
), ya que no se guardarán en la base de datos a menos que ya se haya hecho referencia a ellos.let!
obefore
bloques son los que deberían usarse aquí.Además, nunca lo utilice
before
para activar la ejecución delet
bloques, ¡para estolet!
está hecho!¡dejar! bloques
let!
los bloques se ejecutan en el orden en que están definidos (muy parecido a un bloque anterior). La única diferencia fundamental con los bloques before es que obtiene una referencia explícita a esta variable, en lugar de tener que recurrir a las variables de instancia.Al igual que con los
let
bloques, silet!
se definen varios bloques con el mismo nombre, el más reciente es el que se utilizará en la ejecución. La diferencia principal es que loslet!
bloques se ejecutarán varias veces si se usan así, mientras que ellet
bloque solo se ejecutará la última vez.antes (: cada) bloques
before(:each)
es el bloque anterior predeterminado y, por lo tanto, se puede hacer referencia a él enbefore {}
lugar de especificar el completobefore(:each) {}
cada vez.Es mi preferencia personal usar
before
bloques en algunas situaciones básicas. Usaré antes de los bloques si:before { get :index }
). Aunque podría usarsubject
para esto en muchos casos, a veces se siente más explícito si no necesita una referencia.Si se encuentra escribiendo
before
bloques grandes para sus especificaciones, revise sus fábricas y asegúrese de comprender completamente los rasgos y su flexibilidad.antes (: todos) bloques
Estos solo se ejecutan una vez, antes de las especificaciones en el contexto actual (y sus hijos). Estos se pueden utilizar con gran ventaja si se escriben correctamente, ya que hay ciertas situaciones que pueden reducir la ejecución y el esfuerzo.
Un ejemplo (que difícilmente afectaría el tiempo de ejecución) es simular una variable ENV para una prueba, que solo debería tener que hacer una vez.
Espero que ayude :)
fuente
before(:all)
opción no existe en Minitest. Aquí hay algunas soluciones en los comentarios: github.com/seattlerb/minitest/issues/61its
ya no está en rspec-core. Una forma idiomática más moderna esit { is_expected.to be_awesome }
.Casi siempre, prefiero
let
. La publicación que enlaza especifica quelet
también es más rápida. Sin embargo, a veces, cuando hay que ejecutar muchos comandos, podría usarlobefore(:each)
porque su sintaxis es más clara cuando hay muchos comandos involucrados.En su ejemplo, definitivamente preferiría usar en
let
lugar debefore(:each)
. En términos generales, cuando solo se realiza una inicialización de variable, me gusta usarlet
.fuente
Una gran diferencia que no se ha mencionado es que las variables definidas con
let
no se instancian hasta que se llama por primera vez. Entonces, si bien unbefore(:each)
bloque crearía una instancia de todas las variables, lelet
permite definir una cantidad de variables que podría usar en múltiples pruebas, no las instancia automáticamente. Sin saber esto, sus pruebas podrían volver a morderse si espera que todos los datos se carguen de antemano. En algunos casos, es posible que incluso desee definir una cantidad delet
variables y luego usar unbefore(:each)
bloque para llamar a cadalet
instancia solo para asegurarse de que los datos estén disponibles para empezar.fuente
let!
para definir métodos que se llaman antes de cada ejemplo. Consulte los documentos de RSpec .Parece que está utilizando Machinist. ¡Cuidado, es posible que vea algunos problemas con make! dentro de let (la versión no explosiva) que ocurre fuera de la transacción global del accesorio (si también está utilizando accesorios transaccionales), corrompiendo los datos para sus otras pruebas.
fuente