tutorial rails practices matchers example better best ruby unit-testing rspec

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,

  1. 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 al subject 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), diga subject! en lugar de subject .

  2. 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 (como subject ), 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 de subject / 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.

https://github.com/reachlocal/rspec-style-guide/issues/6