2011-09-14 6 views
29

Ho la seguente validazione nel mio ActiveRecord.Come posso testare la convalida dell'inclusione in Rails usando RSpec

validates :active, :inclusion => {:in => ['Y', 'N']} 

Sto utilizzando quanto segue per testare le convalide del mio modello.

should_not allow_value('A').for(:active) 
should allow_value('Y').for(:active) 
should allow_value('N').for(:active) 

C'è un più pulito e più attraverso il modo di testare questo? Attualmente sto usando RSpec2 e dovrebbe corrispondere.

EDIT

Dopo un po 'guardando in giro ho solo trovato, questo probabilmente un modo 'ok' di prove, shoulda non prevede nulla per questo e per tutti coloro che lo richiede può scrivere il proprio matcher personalizzato per esso . (E probabilmente contribuire al progetto). Alcuni link a discussioni che potrebbero essere interessanti:

  • Collegamenti che indicano quanto sopra. Link 1, Link 2

  • should_ensure_value_in_range Questo si avvicina a quello che può essere utilizzato, ma accetta solo intervalli e non un elenco di valori. L'abbinatore personalizzato può essere basato su questo.

risposta

53

Utilizzare shoulda_matchers

Nelle versioni recenti di shoulda-matchers (almeno a partire dal v2.7.0), è possibile effettuare:

expect(subject).to validate_inclusion_of(:active).in_array(%w[Y N]) 

Questo test verifica che la matrice di valori accettabili nella convalida corrisponda esattamente a questa specifica.

Nelle versioni precedenti,> = v1.4, shoulda_matchers supporta questa sintassi:

it {should ensure_inclusion_of(:active).in_array(%w[Y N]) } 
+0

Per verificare che non consenta altri valori, puoi fare qualcosa del tipo: 'it {should_not allow_value ('?'). Per (: active)}' - come hai detto tu, non puoi controllare tutti i valori possibili, ma facendo questo oltre a controllare tutti i valori consentiti sembra una copertura ragionevole. – bjnord

+0

Il parametro shoulda_matcher a cui si fa riferimento ** funziona ** come originariamente dichiarato, cioè non consente di impostare i valori non nell'array fornito. [Vedi documentazione] (https://github.com/thoughtbot/shoulda-matchers#ensure_inclusion_of). Per buona misura, ho provato questo in un'applicazione Rails e funziona correttamente. –

+1

@LarsLevie - Grazie per il commento. Sembra che abbiano cambiato la convalida per controllare 'disallows_value_outside_of_array?'. Vedi il vecchio https://github.com/thoughtbot/shoulda-matchers/blob/v1.2.0/lib/shoulda/matchers/active_model/ensure_inclusion_of_matcher.rb#L86 rispetto a https://github.com/thoughtbot/shoulda- matchers/blob/15abdf066732828034efea751c2937aa81d080fe/lib/shoulda/matchers/active_model/ensure_inclusion_of_matcher.rb # L90 –

1

ho trovato uno matcher shoulda personalizzato (in uno dei progetti su cui stavo lavorando) che cerca di avvicinarsi per provare qualcosa di simile:

Esempi:

it { should validate_inclusion_check_constraint_on :status, :allowed_values => %w(Open Resolved Closed) } 
it { should validate_inclusion_check_constraint_on :age, :allowed_values => 0..100 } 

Il matcher cerca di garantire che ci sia un vincolo di DB che esplode quando tenta di salvarlo. Cercherò di dare l'essenza dell'idea. Le partite? implementazione fa qualcosa di simile:

begin 
    @allowed_values.each do |value| 
     @subject.send("#{@attribute}=", value) 
     @subject.save(:validate => false) 
    end 
    rescue ::ActiveRecord::StatementInvalid => e 
    # Returns false if the exception message contains a string matching the error throw by SQL db 
    end 

credo che se abbiamo un po 'cambiamo il sopra di dire @subject.save e lasciare che la convalida Rails far saltare in aria, siamo in grado di restituire false quando la stringa eccezione contiene qualcosa che si chiudono corrisponde al messaggio di errore vera eccezione.

So che questo è tutt'altro che perfetto per contribuire al progetto, ma credo che potrebbe non essere una cattiva idea di aggiungere nel tuo progetto come un matcher personalizzato se si vuole veramente testare molto della convalida :inclusion.

+0

Accetterò la mia risposta qui dal momento che non riesco a trovare qualsiasi altra cosa, ma non esitate a criticare come la soluzione di cui sopra può fallire, o se è anche una cattiva idea preoccuparsi di farlo. – jake

23

Se si dispone di più elementi per testare di un valore booleano S/N, allora si potrebbe anche provare.

it "should allow valid values" do 
    %w(item1 item2 item3 item4).each do |v| 
    should allow_value(v).for(:field) 
    end 
end 
it { should_not allow_value("other").for(:role) } 

È possibile anche sostituire il %w() con una costante è stato definito nel modello in modo che mette alla prova che solo i valori costanti sono ammessi.

CONSTANT = %w[item1 item2 item3 item4] 
validates :field, :inclusion => CONSTANT 

Poi il test:

it "should allow valid values" do 
    Model::CONSTANT.each do |v| 
    should allow_value(v).for(:field) 
    end 
end