2012-05-18 14 views
16

Al ir a través de Ruby on Rails Tutorial de Michael Hartl, en la sección donde el autor escribe prueba de integración para validar su página de registro, que ha utilizado código de abajo espineta. Obtuve lo que hace el código, pero no podía entender cómo funcionaba, es decir, no entendía el orden de ejecución.¿Cómo funciona RSpec de esperar que el trabajo en ROR

expect { click_button "Create my account" }.not_to change(User, :count) 

¿Puede alguien explicar la semántica de la cadena de métodos y bloques anteriores y cómo encajan?

+3

Esto no es Capibara, es RSpec. –

+0

@RyanBigg Gracias, solo lo corrigió. – Bedasso

Respuesta

45

que tendría que utilizar expect ... change para verificar que un particular cambia de llamadas a métodos - o no cambia - algún otro valor. En este caso:

expect { click_button "Create my account" }.not_to change(User, :count) 

hará que rspec para hacer lo siguiente:

  1. Run User.count y tenga en cuenta el valor devuelto. (Esto se puede especificar como un receptor y un nombre de método, como (User, :count) en su ejemplo, o como un bloque arbitraria de código, como { User.count }.
  2. Run click_button "Create my account" que es un método Carpincho que simula un clic del ratón sobre un enlace.
  3. ..
  4. Run User.count nuevo
  5. comparar los resultados de # 1 y # 3 Si son diferentes, el ejemplo falla si son la misma, pasa

Otras formas de utilizar expect ... change:..

expect { thing.destroy }.to change(Thing, :count).from(1).to(0) 
expect { thing.tax = 5 }.to change { thing.total_price }.by(5) 
expect { thing.save! }.to raise_error 
expect { thing.symbolize_name }.to change { thing.name }.from(String).to(Symbol) 

Algunos documentos son here.

¿Cómo se hace esto es un poco arcano, y no es en absoluto necesario entender cómo funciona el fin de usarlo. Una llamada al expect está definiendo una estructura para ejecutar rspec, usando la DSL personalizada de rspec y el sistema de "emparejamiento". Gary Bernhardt tiene una bien clara screencast en la que argumenta que el misterio de rspec en realidad cae naturalmente de un lenguaje dinámico como el rubí.No es una buena introducción a usando rspec, pero si tiene curiosidad sobre cómo funciona, puede que le resulte interesante.

ACTUALIZACIÓN

Después de ver su comentario en otra respuesta, voy a añadir un poco sobre el orden de las operaciones. El truco no intuitivo es que es el matcher (change en este caso) que ejecuta todos los bloques. expect tiene una lambda, not_to es un alias para should_not cuyo trabajo es pasar la lambda al emparejador. El emparejador en este caso es change que sabe ejecutar su propio argumento una vez, luego ejecuta el lambda que se pasó (el de expect), luego ejecuta su propio argumento nuevamente para ver si las cosas han cambiado. Es complicado porque la línea parece que debería ejecutarse de izquierda a derecha, pero como la mayoría de las piezas solo están pasando por bloques de código, pueden mezclarlas y barajarlas en el orden que tenga más sentido para el emparejador.

No soy un experto en las partes internas de rspec, pero esa es mi comprensión de la idea básica.

+0

La respuesta más detallada y útil que he leído en SO. Yo recomendaría este 100x si pudiera. ¡Gracias! –

4

He aquí un extracto de de Ryan Bates Railscast on Request Specs and Capybara

require 'spec_helper' 

describe "Tasks" do 
    describe "GET /tasks" do 
    it "displays tasks" do 
     Task.create!(:name => "paint fence") 
     visit tasks_path 
     page.should have_content("paint fence") 
    end 
    end 

    describe "POST /tasks" do 
    it "creates a task" do 
     visit tasks_path 
     fill_in "Name", :with => "mow lawn" 
     click_button "Add" 
     page.should have_content("Successfully added task.") 
     page.should have_content("mow lawn") 
    end 
    end 
end 

Y aquí es un extracto de the docs on RSPec Expectations

describe Counter, "#increment" do 
    it "should increment the count" do 
    expect{Counter.increment}.to change{Counter.count}.from(0).to(1) 
    end 

    # deliberate failure 
    it "should increment the count by 2" do 
    expect{Counter.increment}.to change{Counter.count}.by(2) 
    end 
end 

Así que, básicamente, la

expect { click_button "Create my account" }.not_to change(User, :count) 

forma parte RSpec:

expect {...}.not_to change(User, :count) 

y parte Carpincho

click_button "Create my account" 

(Aquí está a link to the Capyabara DSL - se puede buscar click_button)

Parece que usted está buscando un ejemplo general con los dos. Este no es un ejemplo perfecto, pero podría ser algo como esto:

describe "Tasks" do 
    describe "GET /tasks" do 
    it "displays tasks" do 
     expect { click_button "Create my account" }.not_to change(User, :count) 
    end 
    end 
end 
+0

Tnx para los buenos ejemplos. Estaba más interesado en conocer la semántica de la expresión, como cómo dosis 'change (..)' se ejecuta dos veces y el orden general de ejecución. – Bedasso

Cuestiones relacionadas