2012-05-18 2 views
16

Während Ruby On Rails Tutorial von Michael Hartl, in dem Abschnitt, in dem der Autor Integrationstest schreibt, um seine Anmeldeseite zu validieren, hat er Code-Spinet gebrüllt verwendet. Ich habe bekommen, was der Code tut, aber ich konnte meinen Kopf nicht um den "Wie" -Teil bringen, d. H. Ich konnte die Reihenfolge der Ausführung nicht verstehen.Wie erwartet RSpec Arbeit in ROR

Kann jemand bitte die Semantik der oben genannten Kette von Methoden und Blöcken erklären und wie sie zusammenpassen?

+3

Dies ist nicht Capybara, es ist RSpec. –

+0

@RyanBigg Danke, habe es gerade korrigiert. – Bedasso

Antwort

45

Sie würden expect ... change verwenden, die eine bestimmte Methodenaufruf Änderungen zu überprüfen - oder ändert sich nicht - einen anderen Wert. In diesem Fall:

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

wird rspec führen die folgenden Funktionen ausführen:

  1. Run User.count und notieren Sie den Wert zurückgegeben. (Dies kann als ein Empfänger und ein Verfahren Name angegeben werden, wie (User, :count) in Ihrem Beispiel, oder als ein beliebiger Code-Block, wie { User.count }.
  2. Run click_button "Create my account", die ein Capybara Methode, die auf einen Link per Mausklick simuliert.
  3. ..
  4. Run User.count wieder
  5. Vergleichen sie die Ergebnisse von # 1 und # 3 Wenn sie sich unterscheiden, versagt das Beispiel Wenn sie gleich sind, dann geht es

Andere Möglichkeiten expect ... change zu verwenden:..

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) 

Einige Dokumente sind here.

Wie es ist das ist ein bisschen geheimnisvoll, und es ist überhaupt nicht notwendig zu verstehen, wie es funktioniert, um es zu verwenden. Ein Aufruf an expect definiert eine Struktur für die Ausführung von rspec, die die eigene angepasste DSL und das System von "Matching" von rspec verwendet. Gary Bernhardt hat eine ziemlich saubere screencast, in der er argumentiert, dass das Geheimnis von rspec tatsächlich aus einer dynamischen Sprache wie Rubin herausfällt.Es ist keine gute Einführung in mit rspec, aber wenn Sie neugierig sind, wie alles funktioniert, könnten Sie es interessant finden.

UPDATE

Nachdem Sie Ihren Kommentar auf eine andere Antwort zu sehen, werde ich ein wenig über die Reihenfolge der Operationen hinzuzufügen. Der nicht intuitive Trick ist, dass es der Matcher (change in diesem Fall) ist, der alle Blöcke ausführt. expect hat ein Lambda, not_to ist ein Alias ​​für should_not dessen Aufgabe es ist, das Lambda an den Matcher weiterzugeben. Der Matcher ist in diesem Fall , der weiß, dass er einmal sein eigenes Argument ausführen und dann das Lambda ausführen muss, an das es übergeben wurde (das von expect), dann führe sein eigenes Argument erneut aus, um zu sehen, ob sich die Dinge geändert haben. Es ist schwierig, da die Zeile so aussieht, als würde sie von links nach rechts ausgeführt werden, aber da die meisten Teile nur Blöcke von Code passieren, können sie sie mischen und tun sie in der Reihenfolge, die für den Matcher am sinnvollsten ist.

Ich bin kein Experte für die rspec Interna, aber das ist mein Verständnis der Grundidee.

+0

Die ausführlichste und hilfreichste Antwort, die ich je auf SO gelesen habe. Ich würde diese 100x verbessern, wenn ich könnte. Vielen Dank! –

4

Hier ist ein Auszug aus von 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 

Und hier ist ein Auszug aus 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 

Also im Grunde die

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

Teil RSpec ist:

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

und Teil Capybara

click_button "Create my account" 

(Hier a link to the Capyabara DSL - Sie click_button suchen)

Es klingt wie Sie für ein Gesamt Beispiel mit ihnen beiden suchen. Dies ist nicht ein perfektes Beispiel, aber es etwa so aussehen könnte:

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 für die schönen Beispiele. Ich war mehr daran interessiert, die Semantik des Ausdrucks zu kennen, wie zum Beispiel, wie die Dosisänderung (...) zweimal ausgeführt wird und wie die gesamte Ausführungsreihenfolge ausgeführt wird. – Bedasso