2011-09-24 140 views
66

我已經在Rails中開始了我的TDD之旅,並且遇到了一個關於模型驗證測試的小問題,我似乎找不到解決方案。比方說,我有一個用戶模式,Rails 3.1,RSpec:測試模型驗證

class User < ActiveRecord::Base 
    validates :username, :presence => true 
end 

和一個簡單的測試

it "should require a username" do 
    User.new(:username => "").should_not be_valid 
end 

這正確測試存在驗證,但如果我想更具體的是什麼?例如,在錯誤檢測full_messages對象..

it "should require a username" do 
    user = User.create(:username => "") 
    user.errors[:username].should ~= /can't be blank/ 
end 

我關於初始嘗試(使用should_not be_valid)關注的是,RSpec的不會產生描述性錯誤消息。它只是說「預計有效?返回假,是真的。」但是,第二個測試示例有一個小缺點:它使用create方法而不是新方法來獲取錯誤對象。

我希望我的測試能夠更具體地瞭解他們正在測試的內容,但同時不必觸摸數據庫。

任何人有任何輸入?

回答

91

首先我想說你有一個邪惡的名字。

二,恭喜你用ROR努力進入TDD我保證,一旦你開始你不會回頭。

最簡單快速和骯髒的解決方法是將產生每個測試的這樣的前一個新的有效模式:

before(:each) do 
    @user = User.new 
    @user.username = "a valid username" 
end 

,但我的建議是你辦廠所有的模式,將產生爲你自動生成有效的模型,然後你可以混合個人屬性,看看你的驗證。我喜歡用FactoryGirl此:

基本上,一旦你建立你的測試將是這個樣子:

it "should have valid factory" do 
    FactoryGirl.build(:user).should be_valid 
end 

it "should require a username" do 
    FactoryGirl.build(:user, :username => "").should_not be_valid 
end 

哦雅,這裏是a good railscast這可以解釋這一切比我更好:

好運:)


UPDATE:作爲version 3.0工廠女孩,語法上有改變。我已經修改了我的示例代碼以反映這一點。

+2

非常感謝馬修。有沒有辦法接近我試圖測試的錯誤? X.should_not be_valid對我來說似乎很通用,誰知道在路上會有什麼事會使記錄失效。這個測試然後會在錯誤的地方失敗。順便說一下,我想我已經將你的答案標記爲已接受。我不是嗎? – Feech

+7

對,所以這就是我爲什麼要爭取工廠的原因。您編寫代碼以在一個地方生成一個有效的用戶,然後您編寫一個測試以確保在所有單個測試之前確保其有效,從而確保您可以使其失效。這樣,如果由於某種原因,你改變了你的模型,所以工廠更長的時間產生一個有效的用戶'Factory.build(:user).should be_valid'測試將失敗,你會知道你必須更新你的工廠...得到它? (是的,你接受了我的答案) – Matthew

+0

完美的解釋。再次感謝。 – Feech

41

測試模型驗證(以及更多活動記錄)的更簡單方法是使用像shouldaremarkable這樣的寶石。

他們將允許測試如下:功能或要求規格

describe User 

    it { should validate_presence_of :name } 

end 
+1

這是一個好籤,你必須在模型中的關聯,但要注意,它不會實際嘗試沒有名稱創建一個用戶,並檢查它的有效性 – brafales

+3

@brafales沒有實際上,據我所知這正是早該做的:它將嘗試用空白名稱創建對象,並且它應該給出錯誤。 – nathanvda

+2

你是對的,好像我讀的代碼錯誤https://github.com/thoughtbot/shoulda-matchers/blob/master/lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb – brafales

0

我歷來處理錯誤的內容規範。所以,舉例來說,我有一個類似的規範,我將在下面凝結:

特色規格例

before(:each) { visit_order_path } 

scenario 'with invalid (empty) description' , :js => :true do 

    add_empty_task         #this line is defined in my spec_helper 

    expect(page).to have_content("can't be blank") 

那麼,我有我的模型規範測試的東西是否是有效的,但後來我功能規範測試錯誤消息的確切輸出。僅供參考,這些功能規格要求水豚可以找到here

15

試試這個:

it "should require a username" do 
    user = User.create(:username => "") 
    user.valid? 
    user.errors.should have_key(:username) 
end 
+0

這是我最喜歡的,很紮實,檢查鍵和不是消息,這是一個細節 – ecoologic

+3

可以只使用用戶= User.new(:用戶名=>「」) 避免撞到分貝 –

+0

@TaufiqMuhammadi'new'不會碰到分貝級驗證,例如唯一性指標約束。 – mnort9

2
在新版本的RSpec

,你應該使用期望而應,否則你會得到警告:

it "should have valid factory" do 
    expect(FactoryGirl.build(:user)).to be_valid 
end 

it "should require a username" do 
    expect(FactoryGirl.build(:user, :username => "")).not_to be_valid 
end 
+0

您還應該在示例名稱中使用現在時動詞而不是應該使用現在時動詞。上面的內容可以被重寫爲「」有一個有效的工廠「'和'」需要一個用戶名「'」。 – BrunoFacca

0

像@nathanvda說,我會好好把握Thoughtbot的Shoulda Matchers寶石。隨着搖擺,您可以按照以下方式編寫測試,以測試是否存在以及任何自定義錯誤消息。

RSpec.describe User do 

    describe 'User validations' do 
    let(:message) { "I pitty da foo who dont enter a name" } 

    it 'validates presence and message' do 
    is_expected.to validate_presence_of(:name). 
     with_message message 
    end 

    # shorthand syntax: 
    it { is_expected.to validate_presence_of(:name).with_message message } 
    end 

end