2012-05-18 90 views
16

在邁克爾哈特爾的Ruby On Rails教程中,作者在撰寫集成測試以驗證其註冊頁面的部分,他使用了代碼spinet下圖。我得到了代碼的功能,但卻無法理解'如何'部分,即無法理解執行順序。RSpec如何在ROR中工作

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

有人可以請解釋上述方法和塊的鏈的語義,以及它們如何組合在一起?

+3

這不是水豚,它是RSpec。 –

+0

@RyanBigg謝謝,剛剛糾正它。 – Bedasso

回答

45

你會使用expect ... change來驗證一個特定的方法調用的變化 - 或不改變 - 一些其他的價值。在這種情況下:

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

會導致RSpec的做到以下幾點:

  1. 運行User.count並注意返回的值。 (這可以在例如被指定爲接收器和方法名,像(User, :count),或者作爲代碼的任意塊,像{ User.count }
  2. 運行click_button "Create my account"其是水豚方法模擬鏈路上的鼠標點擊。
  3. 運行User.count再次
  4. 比較的#1和#3的結果如果它們不同,該示例失敗如果它們是相同的,它通過

使用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) 

一些文檔是here

它是如何做到這一點有點神祕,並沒有必要了解它是如何工作的,以便使用它。對expect的調用正在使用rspec自己的定製DSL和「匹配器」系統定義rspec執行的結構。加里伯恩哈特有一個相當整潔的screencast,其中他認爲rspec的奧祕實際上自動從一個動態的語言,如紅寶石掉落。使用 rspec並不是的一個很好的介紹,但如果你對它的工作原理感到好奇,你可能會覺得它很有趣。

UPDATE

看到另一個回答您的評論後,我將添加有關操作的整理了一下。不直觀的技巧是執行所有塊的匹配器(在這種情況下爲change)。 expect有一個lambda,not_toshould_not的別名,其作用是將lambda傳遞給匹配器。在這種情況下,匹配器是change,它知道一次執行自己的參數,然後執行它傳遞的lambda(expect中的那個),然後再次運行自己的參數以查看是否發生了變化。這很棘手,因爲該行看起來應該從左到右執行,但由於大部分代碼只是傳遞代碼塊,因此它們可以將它們混合成匹配器最有意義的順序。

我不是rspec內部專家,但這是我對基本想法的理解。

+0

我曾閱讀過最詳細,最有用的答案。如果可以的話,我會贊成這個100倍。謝謝! –

4

下面是從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 

摘錄下面是從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 

所以基本上的摘錄中,

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

是部分RSpec的:

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

和一部分水豚

click_button "Create my account" 

(這裏是a link to the Capyabara DSL - 您可以搜索click_button

這聽起來像你正在尋找與他們兩人的總例子。這不是一個很好的例子,但它可能是這個樣子:

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爲好例子。我更感興趣的是知道表達式的語義,比如劑量'change(..)'如何執行兩次以及執行的總體順序。 – Bedasso