2013-02-28 20 views
5

Ho il seguente validatore nel mio modello:RSpec validatore test personalizzati

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 

Come posso provarlo con Rspec?

Ecco quello che ho provato finora: (grazie a 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 

ma ottengo i seguenti errori:

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

Che cosa sto facendo di sbagliato? E come posso raggiungere il mio obiettivo? Qualsiasi aiuto o suggerimento sarebbe apprezzato. Grazie.

risposta

11

Il problema è che sei in attesa @time_event.errors a comportarsi come un array di stringhe. Non lo fa, restituisce ActiveModel :: Errors. Come altri hanno sottolineato, è inoltre necessario per innescare le convalide con una chiamata a 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

Hai ragione Ho bisogno di aggiungere il full_messages per ottenere l'errore. Comunque, come detto l'altro, ho bisogno di testare realmente la validazione con 'valido?' – siekfried

+0

Esatto. Ho aggiornato la risposta. –

1

Non ci sono errori perché non è stato chiamato un evento che attiva gli errori. Ciò accade normalmente quando un record viene creato o salvato. Non si può decidere di colpire il database nel tuo test e anche se è possibile utilizzare il metodo valid? in questo modo:

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 

me personalmente metterei questi due test in un dato valido? è chiamato nel primo caso.

Anche un minore: if record.end_time è migliore di if !record.end_time.nil?. (A mio parere almeno .... :-))

+0

hai ragione, ma, come @Benjamin Sullivan ha suggerito, ho anche bisogno di aggiungere le full_messages agli errori in modo che il mio pass di prova. Grazie anche per il minore :) – siekfried

0

Penso che il record non sia stato convalidato, quindi il validatior non è stato eseguito e non è stato segnalato alcun errore. Puoi vederlo nell'output del codice. "Convalidato: false"

prova:

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

Non hai testato la convalida in realtà, più vorrei suggerire di fare un singolo spec.

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

questa soluzione funziona per me (utilizzando Mongoid):

Il modello

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 

La prova:

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

Quindi nel tuo caso I' d scrivere un test come questo (if usando 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