2012-10-29 81 views
2

我有幾個RSpec控制器測試。一些工作,有些不這樣做,我試圖弄清楚在地球上如何修復它們並使它們更加高效簡化和正確RSpec控制器測試

理想情況下,我想看看我是否可以將每個規範都轉換爲以下形式

subject { ... } 
    it { ... } 
    it { ... } 
    it { ... } 

請注意,對於我的所有控制器規格,我已經爲實際控制器操作編寫了宏。這些宏都經過了測試,並且都可以正常工作,並且這些名稱使得它們顯得非常明顯。

我的「創建」測試:

formats ||= ["html", "js"] 
formats.each do |format| 
    context "valid attributes" do 
    subject { do_post_create(:customer, valid_attributes, format) } 
     its(:response_code) { should eq(302)} 
     it { should redirect_to admin_customer_path(Customer.find_by_id(???))} 
     it { expect { subject }.to change(Customer, :count).by(1) } 
    end 

    context "invalid attributes" do 
    subject { do_post_create(:customer, invalid_attributes, format) } 
     its(:response_code) { should eq(200)} 
     it { should render_template :new } 
     it { expect { subject }.to_not change(Customer, :count).by(1) } 
    end 
end 

在這種規範,我一直在試圖找出一些方法來擺脫後聲明新創建的對象的ID。我嘗試過「Customer.last」,但這似乎不起作用。有什麼想法嗎?

我的「更新」規格:

formats ||= ["html", "js"] 
formats.each do |format| 
    context "valid attributes" do 
    let(:object) { FactoryGirl.create(:customer) } 
    subject { do_put_update(class_to_symbol(model), object.id, attributes, format) } 
     its(:response_code) { should eq(302)} 

    it "does alter #{model}" do 
     do_put_update(class_to_symbol(model), object.id, attributes, format) 
     assigns(:customer).should eq(object) 
     flash[:notice].should =~ /Success/ 
     object.reload 
     attributes.each do |key, value| 
     object.send(key.to_s).should eq(value) 
     end 
    end 
    end 
    context "invalid attributes" do 
    let(:object) { FactoryGirl.create("customer") } 
    let(:invalid_attributes) { {:username => "!"} } 
    subject { do_put_update(class_to_symbol(model), object.id, invalid_attributes, format) } 
     its(:response_code) { should eq(200)} 

    it "does not alter #{model}" do 
     do_put_update(class_to_symbol(model), object.id, invalid_attributes, format) 
     assigns(:customer).should eq(object) 
     flash[:notice].should =~ /Fail/ 
     object.reload 
     attributes.each do |key, value| 
     object.send(key.to_s).should_not eq(value) 
     end 
    end 
    end 
end 

在更新測試,我想試圖表達的第二塊以更簡潔的方式,最好的方式,我可以使用相同的「主題「所有測試的聲明。那可能嗎?

回答

3

我認爲你在考慮這些規格。不要試圖將每個規範強制爲預定義的格式(subject/it/...)編寫規範,以便他們清楚地記錄應該發生什麼,然後然後嘗試重構代碼。

案例:控制器操作使用隱式subjectsubjectits意在與對象一起使用,而不是方法,並且只有在使用這種方式時纔有意義。因此,例如,這是有道理的:

subject { [1, 2, 3, 4] } 
its(:size) { should == 4 } 

這裏,這是絕對清楚的是什麼測試:4個元素的數組的大小爲4

但是,當你寫:

subject { do_post_create(:customer, valid_attributes, format) } 
its(:response_code) { should eq(302)} 

從您沒有檢查do_post_create操作中獲取響應代碼的位置並不十分清楚。你說這些宏的名字「很明顯地表明它們做了什麼」,但是它們並沒有使它變得相當明顯它們將返回,這是使用隱式主題的關鍵,因爲它是返回值變成主題。

這將是更清楚只是寫:

it "responds with a 302" do 
    do_post_create(:customer, valid_attributes, format) 
    response.should eq(302) 
end 

我也不建議使用和不使用隱式主題混合功能,因爲它使還比較混亂您實際測試。例如,在您的無效屬性context區塊中,您設置了一個主題,但在第二個規範中,您實際上測試了customerassigns(:customer).should eq(object))的分配,因此基本上該主題與此測試無關。(然而,通過在這裏設置主題,然後不使用它,你實際上發送了一個PUT請求兩次(通過do_put_update),這肯定會導致問題 - 再次,另一個原因是不要在subject塊中發出請求。)

我可以繼續,但我認爲你會得到這張照片。如果你能在不損害可讀性的情況下做到這一點,製作規格簡短而又甜美,但在這種情況下,我認爲你已經過度了。

只是我的兩分錢,希望它有幫助。

p.s.如果上述觀點似乎有點偏激,讀documentation for implicit subjects,在那裏你會看到,他們其實對推薦在面向公衆的測試使用隱式主題都:

雖然下面的例子演示主題如何能作爲一個面向用戶的概念,我們建議您保留它以支持自定義匹配器和/或擴展庫,從而將其用於示例中。

+0

呃,這些都是非常好的點 - 考慮我相信。順便說一句,爲什麼「Customer.last」會在我的規格中返回零? – Bryce