ruby - rails - rspec tutorial
¿Cuál es la diferencia entre el sujeto de RSpec y let? ¿Cuándo deberían usarse o no? (3)
http://betterspecs.org/#subject
tiene información sobre el
subject
y
let
.
Sin embargo, todavía no estoy claro sobre la diferencia entre ellos.
Además, la publicación SO
¿Cuál es el argumento en contra de usar antes, let y subject en las pruebas de RSpec?
Dijo que es mejor no usar ni
subject
ni
let
.
¿Adónde debo ir?
Estoy muy confundido.
Resumen: el tema de RSpec es una variable especial que se refiere al objeto que se está probando.
Las expectativas se pueden establecer implícitamente, lo que admite ejemplos de una línea.
Es claro para el lector en algunos casos idiomáticos, pero por lo demás es difícil de entender y debe evitarse.
Las variables
let
de RSpec son solo variables perezosamente instanciadas (memorizadas).
No son tan difíciles de seguir como el tema, pero aún pueden conducir a pruebas enredadas, por lo que deben usarse con discreción.
El tema
Cómo funciona
El sujeto es el objeto que se prueba. RSpec tiene una idea explícita del tema. Puede o no estar definido. Si es así, RSpec puede invocar métodos en él sin hacer referencia explícita a él.
Por defecto, si el primer argumento para un grupo de ejemplo más externo (
describe
o bloque de
context
) es una clase, RSpec crea una instancia de esa clase y la asigna al sujeto.
Por ejemplo, los siguientes pases:
class A
end
describe A do
it "is instantiated by RSpec" do
expect(subject).to be_an(A)
end
end
Puede definir el tema usted mismo con
subject
:
describe "anonymous subject" do
subject { A.new }
it "has been instantiated" do
expect(subject).to be_an(A)
end
end
Puede asignarle un nombre al sujeto cuando lo defina:
describe "named subject" do
subject(:a) { A.new }
it "has been instantiated" do
expect(a).to be_an(A)
end
end
Incluso si nombra el tema, aún puede referirse a él de forma anónima:
describe "named subject" do
subject(:a) { A.new }
it "has been instantiated" do
expect(subject).to be_an(A)
end
end
Puede definir más de un tema con nombre.
El sujeto nombrado más recientemente definido es el
subject
anónimo.
Sin embargo, el tema está definido,
-
Se instancia de manera perezosa. Es decir, la instanciación implícita de la clase descrita o la ejecución del bloque pasado al
subject
no sucede hasta que se haga referencia alsubject
o al sujeto nombrado en un ejemplo. Si desea que su sujeto explícito sea instanciado con entusiasmo (antes de que se ejecute un ejemplo en su grupo), digasubject!
en lugar desubject
. -
Las expectativas se pueden establecer implícitamente (sin escribir el
subject
o el nombre de un sujeto nombrado):describe A do it { is_expected.to be_an(A) } end
El tema existe para admitir esta sintaxis de una línea.
Cuando usarlo
Un
subject
implícito (inferido del grupo de ejemplo) es difícil de entender porque
- Se crea una instancia detrás de escena.
-
Ya sea que se use implícitamente (llamando
is_expected
sin un receptor explícito) o explícitamente (comosubject
), no le da al lector información sobre el rol o la naturaleza del objeto sobre el cual se llama la expectativa. - La sintaxis de ejemplo de una línea no tiene una descripción de ejemplo (el argumento de cadena en la sintaxis de ejemplo normal), por lo que la única información que el lector tiene sobre el propósito del ejemplo es la expectativa misma.
Por lo tanto, solo es útil usar un tema implícito cuando es probable que el contexto sea bien entendido por todos los lectores y realmente no haya necesidad de una descripción de ejemplo . El caso canónico está probando las validaciones de ActiveRecord con los comparadores de hombro:
describe Article do
it { is_expected.to validate_presence_of(:title) }
end
Un tema anónimo explícito (definido con un
subject
sin nombre) es un poco mejor, porque el lector puede ver cómo se instancia, pero
- todavía puede poner la instanciación del tema lejos de donde se usa (por ejemplo, en la parte superior de un grupo de ejemplo con muchos ejemplos que lo usan), lo que aún es difícil de seguir, y
- tiene los otros problemas que tiene el sujeto implícito.
Un sujeto con nombre proporciona un nombre que revela la intención, pero la única razón para usar un sujeto con nombre en lugar de una variable
let
es si desea usar el sujeto anónimo en alguna ocasión, y simplemente explicamos por qué el sujeto anónimo es difícil de entender .
Por lo tanto, los
usos legítimos de un
subject
anónimo explícito o un sujeto nombrado son muy raros
.
let
variables
Cómo trabajan ellos
let
variables sean como sujetos nombrados excepto por dos diferencias:
-
se definen con
let
/let!
en lugar desubject
/subject!
-
no establecen el
subject
anónimo ni permiten que se invoquen expectativas implícitamente.
Cuando usarlos
Es completamente legítimo usar
let
para reducir la duplicación entre ejemplos.
Sin embargo, hágalo solo cuando no sacrifique la claridad de la prueba.
El momento más seguro para usar
let
es cuando el propósito de la variable
let
es completamente claro en su nombre (para que el lector no tenga que encontrar la definición, que podría estar a muchas líneas de distancia, para comprender cada ejemplo) y se usa en el De la misma manera en todos los ejemplos.
Si alguna de esas cosas no es cierta, considere definir el objeto en una variable local antigua o llamar a un método de fábrica directamente en el ejemplo.
let!
Es arriesgado, porque no es perezoso.
Si alguien agrega un ejemplo al grupo de ejemplo que contiene
let!
, pero el ejemplo no necesita
let!
variable,
-
ese ejemplo será difícil de entender, ¡porque el lector verá el
let!
variable y preguntarse si y cómo afecta el ejemplo -
¡el ejemplo será más lento de lo necesario, debido al tiempo que lleva crear el
let!
variablle
¡Así que usa
let!
, en todo caso, solo en grupos de ejemplos pequeños y simples donde es menos probable que los futuros escritores de ejemplos caigan en esa trampa.
El fetiche de una sola expectativa por ejemplo
Hay un uso excesivo común de temas o variables que vale la pena discutir por separado. A algunas personas les gusta usarlos así:
describe ''Calculator'' do
describe ''#calculate'' do
subject { Calculator.calculate }
it { is_expected.to be >= 0 }
it { is_expected.to be <= 9 }
end
end
(Este es un ejemplo simple de un método que devuelve un número para el que necesitamos dos expectativas, pero este estilo puede tener muchos más ejemplos / expectativas si el método devuelve un valor más complicado que necesita muchas expectativas y / o tiene muchos efectos secundarios que todos necesitan expectativas)
Las personas hacen esto porque han escuchado que uno solo debe tener una expectativa por ejemplo (que se mezcla con la regla válida de que solo se debe probar una llamada al método por ejemplo) o porque están enamorados de la trampa de RSpec.
¡No lo hagas, ya sea con un sujeto anónimo o con nombre o con una variable
let
!
Este estilo tiene varios problemas:
- El sujeto anónimo no es el sujeto de los ejemplos, el método es el sujeto. Escribir la prueba de esta manera arruina el lenguaje, lo que hace que sea más difícil de pensar.
- Como siempre con los ejemplos de una línea, no hay espacio para explicar el significado de las expectativas.
- El sujeto tiene que ser construido para cada ejemplo, que es lento.
En cambio, escriba un solo ejemplo:
describe ''Calculator'' do
describe ''#calculate'' do
it "returns a single-digit number" do
result = Calculator.calculate
expect(result).to be >= 0
expect(result).to be <= 9
end
end
end
Subject
y
let
son solo herramientas para ayudarlo a ordenar y acelerar sus pruebas.
La gente de la comunidad rspec los usa, así que no me preocuparía si está bien usarlos o no.
Se pueden usar de manera similar, pero tienen propósitos ligeramente diferentes.
Subject
permite declarar un sujeto de prueba y luego reutilizarlo para cualquier número de casos de prueba siguientes.
Esto reduce la repetición de código (SECANDO su código)
Let
es una alternativa a
before: each
bloque, que asigna datos de prueba a variables de instancia.
Let
que te dé un par de ventajas.
Primero, almacena en caché el valor sin asignarlo a una variable de instancia.
En segundo lugar, se evalúa perezosamente, lo que significa que no se evalúa hasta que una especificación lo requiera.
Por lo tanto,
let
ayude a acelerar sus pruebas.
También creo que
let
es más fácil de leer
subject
es lo que se está probando, generalmente una instancia o una clase.
let
es para asignar variables en sus pruebas, que se evalúan perezosamente en comparación con el uso de variables de instancia.
Hay algunos buenos ejemplos en este hilo.