2013-02-28 240 views
5

我在我的模型如下驗證:RSpec的測試自定義驗證

class ContinuumValidator < ActiveModel::Validator 
    def validate(record) 
    if !record.end_time.nil? and record.end_time < record.start_time 
     record.errors[:base] << "An event can not be finished if it did not start yet..." 
    end 
    end 
end 

class Hrm::TimeEvent < ActiveRecord::Base 
    validates_with ContinuumValidator 
end 

如何使用Rspec的我測試它?

這裏是我到目前爲止已經試過:(感謝zetetic

describe "validation error" do 
    before do 
    @time_event = Hrm::TimeEvent.new(start_time: "2012-10-05 10:00:00", end_time: "2012-10-05 09:00:00", event_type: 2) 
    end 

    it "should not be valid if end time is lower than start time" do 
    @time_event.should_not be_valid 
    end 

    it "raises an error if end time is lower than start time" do 
    @time_event.errors.should include("An event can not be finished if it did not start yet...") 
    end 
end 

,但我得到了以下錯誤:

1) Hrm::TimeEvent validation error raises an error if end time is lower than start time 
    Failure/Error: @time_event.errors.should include("An event can not be finished if it did not start yet...") 

    expected #<ActiveModel::Errors:0x007fd1d8e02c50 @base=#<Hrm::TimeEvent id: nil, start_time: "2012-10-05 08:00:00", end_time: "2012-10-05 07:00:00", event_type: 2, employee_id: nil, created_at: nil, updated_at: nil, not_punched: false, validated: false, replace_id: nil>, @messages={}> to include "An event can not be finished if it did not start yet..." 

    Diff: 
    @@ -1,2 +1,5 @@ 
    -["An event can not be finished if it did not start yet..."] 
    +#<ActiveModel::Errors:0x007fd1d8e02c50 
    + @base= 
    + #<Hrm::TimeEvent id: nil, start_time: "2012-10-05 08:00:00", end_time: "2012-10-05 07:00:00", event_type: 2, employee_id: nil, created_at: nil, updated_at: nil, not_punched: false, validated: false, replace_id: nil>, 
    + @messages={}> 

我在做什麼錯?我怎樣才能達到我的目標? 任何幫助或建議,將不勝感激。 謝謝。

回答

11

的問題是,你希望@time_event.errors表現得像一個字符串數組。它不,它返回ActiveModel :: Errors。正如其他人所指出的,你還需要觸發一個調用驗證到valid?

it "raises an error if end time is lower than start time" do 
    @time_event.valid? 
    @time_event.errors.full_messages.should include("An event can not be finished if it did not start yet...") 
end 
+0

你說得對,我需要添加full_messages來獲取錯誤。然而像其他人說的那樣,我需要實際測試驗證'有效嗎?' – siekfried 2013-02-28 13:47:02

+0

沒錯。我更新了答案。 – 2013-02-28 13:51:01

1

沒有錯誤,因爲您沒有調用觸發錯誤的事件。這通常在創建或保存記錄時發生。您可能不希望擊中數據庫在您的測試,雖然,然後你可以使用這樣的方法valid?

it "raises an error if end time is lower than start time" do 
    @time_event.valid? 
    @time_event.errors.should include("An event can not be finished if it did not start yet...") 
end 

我個人會把這兩項測試爲一體,因爲有效嗎?在第一種情況下被稱爲。

也是次要的:if record.end_timeif !record.end_time.nil?好。 (在我看來,至少...... :-))

+0

你是對的,但像@Benjamin Sullivan建議的,我還需要添加full_messages到錯誤,以便我的測試通過。也感謝未成年人:) – siekfried 2013-02-28 13:48:49

0

我認爲記錄沒有驗證,因此validatior沒有運行,也沒有發現錯誤。你可以在代碼輸出中看到它。 「驗證:假」

嘗試:

it "raises an error if end time is lower than start time" do 
    @time_event.valid? 
    @time_event.errors.should include("An event can not be finished if it did not start yet...") 
end 
0

您還沒有測試驗證實際,再加上我會建議你做一個規範。

describe "validation error" do 
    before { @time_event = Hrm::TimeEvent.new(start_time: "2012-10-05 10:00:00", end_time: "2012-10-05 09:00:00", event_type: 2) } 

    it "raises an error if end time is lower than start time" do 
    @time_event.valid? 
    @time_event.errors.should include("An event can not be finished if it did not start yet...") 
    end 
end 

class ContinuumValidator < ActiveModel::Validator 
    def validate(record) 
    if record.end_time and record.end_time < record.start_time 
     record.error.add_to_base << "An event can not be finished if it did not start yet..." 
    end 
    end 
end 
1

該解決方案對我的作品(使用Mongoid):

模型

class OpLog 
... 
field :from_status, type: String 
field :to_status, type: String 
... 
validate :states_must_differ 

def states_must_differ 
    if self.from_status == self.to_status 
    errors.add(:from_status, "must differ from 'to_status'") 
    errors.add(:to_status, "must differ from 'from_status'") 
    end 
end 
... 
end 

測試:

it 'is expected to have different states' do 
    expect { create(:oplog, from_status: 'created', to_status: 'created').to raise_error(Mongoid::Errors::Validations) } 
end 

所以你的情況我d寫這樣的測試(如果使用ActiveRecord):

it 'raises an error if end time is lower than start time' do 
    expect { create(Hrm::TimeEvent.new(start_time: "2012-10-05 10:00:00", end_time: "2012-10-05 09:00:00", event_type: 2)) }.to raise_error(ActiveRecord::Errors) 
end