2016-04-18 9 views
2

Schrieb einen benutzerdefinierten Validator in meinem Rails-Projekt und möchte einen Test schreiben, wenn nil in den Datensatz übergeben wird.Benutzerdefinierter Validator-Test - enthält Fehler?

Der Validator Code

class FutureValidator < ActiveModel::EachValidator 
    def validate_each(record, attribute, value) 
    if value == nil 
     record.errors[attribute] << "can't be nil" 
    elsif value <= Time.now 
     record.errors[attribute] << (options[:message] || "can't be in the past!") 
    end 
    end 
end 

Mögliche Test

test "future validator rejects nil values" do 
    @obj.future = nil 
    assert_includes @obj.errors 
end 

Ich mag würde, um nicht nur einen Test schreiben, dass assert_not @obj.valid? prüft aber zeigen tatsächlich, dass die Nachricht Fehler zurückgeschickt werden. Wenn das zu viel verlangt, werde ich mich damit begnügen zu wissen, dass eine Fehlermeldung zurückkommt, aber zur Zeit funktioniert mein Test nicht.

Es kehrt

ArgumentError: wrong number of arguments (1 for 2..3)

aktualisieren immer nah an einem grünen Test

test "future validator rejects nil values" do 
    @obj.future = nil 
    @obj.valid? 
    assert_includes @obj.errors.messages, {future: ["can't be nil"]} 
    end 

kehrt

FutureValidatorTest#test_future_validator_rejects_nil_values [/Users/rwdonnard/WorkSpace/charter-pay-api/test/models/future_validator_test.rb:42]: Expected {:future=>["can't be nil"]} to include {:future=>["can't be nil"]}.

+0

Wie geht es Ihnen es benutzen? Können Sie den Modellcode dort posten, wo er aufgerufen wird? Ich verstehe nicht wirklich, warum Sie überprüfen, ob der Wert Null ist, Sie implementieren den Anwesenheitsvalidierer erneut. Sie könnten diesen Teil entfernen und 'validates: date, present: true, future: true' verwenden. –

+0

@ j-dexx entschuldigen Sie meine Ignoranz, aber würde' presence: true' eine ausführliche/menschenlesbare Fehlermeldung liefern, die sie 'nil bestanden haben '? – CheeseFry

+1

die Standardmeldung ist "kann nicht leer sein" –

Antwort

3

Die Frage, wie Sie testen zu sein scheint Ihre Klasse und höchstwahrscheinlich die exce ption wird von assert_includes ausgelöst. assert_includes erwartet mindestens 2 Argumente, wobei das erste eine Sammlung ist und das zweite das erwartete Objekt ist, in Ihrem Fall ein Array von Fehlern und der Fehler, den Sie erwarten. Auch Ihr Test ist zum Scheitern verurteilt, wenn Sie nicht die @obj.errors Sammlung füllen, etwas, das @obj.valid?

Ihr Test sollte so aussehen zu nennen erfordert:

test "future validator rejects nil values" do 
    @obj.future = nil 
    @obj.valid? 
    assert_includes @obj.errors.messages, { future: ["can't be nil"] } 
end 

diese Weise können Sie sicherstellen, dass Ihr Modell ungültig, wenn future.nil? unabhängig von anderen gültigen Validierungen.

Ich würde auch vorschlagen, dass Sie in Ihrem benutzerdefinierten Validator nicht nach Anwesenheit suchen, da Rails bereits einen Weg dafür bietet. Sie könnten Ihren Validator aussehen wie dieses:

class FutureValidator < ActiveModel::EachValidator 
    def validate_each(record, attribute, value) 
    if value <= Time.now 
     record.errors[attribute] << (options[:message] || "can't be in the past!") 
    end 
    end 
end 

und Setup-Validierung in Ihrem Modell wie folgt aus:

class SomeClass < ActiveRecord::Base 
    validates :future, presence: true, future: true 
end 

Sie können auch Ihre Tests wie vereinfachen:

test "is invalid with nil future date" do 
    @obj.future = nil 
    @obj.valid? 
    assert_includes @obj.errors.messages[:future], "can't be nil" 
end 

test "future validator rejects past dates" do 
    @obj.future = Date.new(1987, 1, 1) 
    @obj.valid? 
    assert_includes @obj.errors.messages[:future], "can't be in the past!" 
end 
+0

Das macht Sinn. Wenn ich den Code ausführe, erhalte ich den folgenden Fehler.'Erwartet # >, @ messages = {: future => ["kann nicht nil sein"]}> sollte {: future => ["kann nicht nil sein"]} enthalten. ' – CheeseFry

+0

Ich denke, du solltest gegen' @ object.errors.messages' nachsehen, weil '@ object.errors' ist keine Sammlung, sondern eine Instanz der Klasse' ActiveModel :: Errors'. Ich werde den Code aktualisieren, um dies zu berücksichtigen. –

+0

Wenn ich es von 'assert_includes' zu' assert_equal' ändere, bekam ich, was ich erwartet hatte. Ist das eine faire Antwort? – CheeseFry

Verwandte Themen