2013-02-28 14 views
5

ich folgendes Validator in meinem Modell haben:RSpec Test benutzerdefinierten Validator

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 

Wie kann ich es testen Rspec mit?

Hier ist, was ich versucht habe, so weit: (dank 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 

Aber ich bekomme die folgenden Fehler:

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={}> 

Was mache ich falsch? Und wie kann ich mein Ziel erreichen? Jede Hilfe oder Anregung wäre willkommen. Danke.

Antwort

11

Das Problem ist, dass Sie @time_event.errors erwar wie ein Array von Strings zu verhalten. Tut es nicht, es gibt ActiveModel :: Errors zurück. Wie andere erwähnt, müssen Sie auch die Validierungen mit einem Aufruf an valid? auszulösen:

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

Sie haben Recht, ich muss die full_messages hinzufügen, um den Fehler zu erhalten. Wie auch der andere sagte, muss ich die Validierung mit "valid?" Tatsächlich testen. – siekfried

+0

Das stimmt. Ich habe die Antwort aktualisiert. –

1

Es gibt keine Fehler, weil Sie kein Ereignis aufgerufen haben, das die Fehler auslöst. Dies geschieht normalerweise, wenn ein Datensatz erstellt oder gespeichert wird. Sie können die Datenbank nicht in Ihrem Test wollen, obwohl schlagen und dann können Sie die Methode valid? wie folgt verwenden:

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 

mich persönlich würde diese zwei Tests in einem seit gültig setzen? heißt im ersten Fall.

Auch ein kleiner: if record.end_time ist besser als if !record.end_time.nil?. (Meiner Meinung nach zumindest .... :-))

+0

Sie haben Recht, aber wie @Benjamin Sullivan vorgeschlagen, ich brauche auch den full_messages auf die Fehler hinzufügen, so dass mein Testdurchlauf. Danke auch für den kleinen :) – siekfried

0

Ich denke, der Datensatz wurde nicht validiert, daher wurde der Validator nicht ausgeführt und es wurde kein Fehler gemeldet. Sie können dies in der Codeausgabe sehen. "Bestätigt: false"

Versuch:

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

Sie haben nicht getestet, um die Validierung tatsächlich plus würde ich vorschlagen, dass Sie eine einzelne Spezifikation zu machen.

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

Diese Lösung funktioniert für mich (mit Mongoid):

Das Modell

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 

Der Test:

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

Also in Ihrem Fall ich d schreibe einen Test wie diesen (wenn Active verwenden):

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