2014-04-23 33 views
1

我有上有唯一性驗證ActiveRecord模型:如何在沒有數據庫的ActiveRecord模型規範中模擬唯一性驗證錯誤?

class Profile < ActiveRecord::Base 
    # fields: :name, :slug 

    before_validation :set_default_slug_from_name 

    validates :slug, uniqueness: {case_sensitive: false}, 
        unless: -> { |p| p.slug.blank? } 

    # ... 
end 

現在,書寫規範這個模型時,我想模擬唯一性驗證錯誤而無需訪問數據庫所以我可以測試

describe Profile 
    before { subject.name = "Bob Greenfield" } 

    it "modifies the beginning of the slug if there is a duplicate" do 
    # simulate uniqueness conflict (duplicate record) here 
    subject.valid? 
    expect(subject.slug).to match(/^\w+-bob-greenfield$/) 
    end 
end 

我挖成實現像UniquenessValidator和嘗試的東西Rails code

依賴於這樣的錯誤一些模型行爲
allow_any_instance_of(ActiveRecord::Relation).to receive(:exists?).and_return(true) 
# ... 

但是,這似乎並沒有工作。

回答

3

我認爲你在這裏試圖去一點點太深。儘管閱讀Rails源代碼並理解它的工作原理是件好事,但嘲笑Rails內部使用的每個類實例並不是一個好主意。在這種情況下,與其他一些驗證器相比,UniquenessValidator確實取決於數據庫,因此您應該:

a。允許自己擊中數據庫。在這種情況下,這不是一個巨大的開銷,也許是實現這一目標最務實的方式。你甚至可以在規範中的評論中使用「重複記錄」,那麼爲什麼不在那裏有記錄? 10個案例中有9個案例是正確的。畢竟你正在檢查一種ActiveRecord :: Base對象。

b。檢查獨立於rails驗證的行爲。無論如何應該這樣做來測試你的首選格式的slu。。它更好地確保默認slug在驗證之前有效。 這裏的缺點是,在這個調用和實際驗證之前有一個小小的機會,slug會被其他人所採用,但是它與驗證中構建的Rails一樣,所以我不會擔心它 - 你會結束錯誤發生,下次嘗試將很可能成功。

it "modifies the beginning of the slug on validation if there is a duplicate" do 
    Profile.stub(:slug_exists?).with("bob-greenfield").and_return(true) 
    Profile.stub(:slug_exists?).with("1-bob-greenfield").and_return(true) 
    Profile.stub(:slug_exists?).with("2-bob-greenfield").and_return(false) 

    subject.set_default_slug_from_name 
    subject.slug.should == "2-bob-greenfield" 
end 

並且您已經知道Rails在驗證之前調用,因此您不必測試此行爲。

另外,最好確保你對數據庫有限制,Rails的唯一性不夠:http://robots.thoughtbot.com/the-perils-of-uniqueness-validations

相關問題