2015-04-01 5 views
31

Ich möchte nach vielen Änderungen in einem Modell überprüfen, wenn Sie ein Formular in einer Feature-Spezifikation senden. Ich möchte zum Beispiel sicherstellen, dass der Benutzername von X in Y geändert wurde und dass das verschlüsselte Passwort um einen beliebigen Wert geändert wurde.RSpec: Erwarten Sie, mehrere zu ändern

Ich weiß, dass es schon einige Fragen dazu gibt, aber ich fand keine passende Antwort für mich. Die genaueste Antwort scheint der ChangeMultiple Matcher von Michael Johnston hier zu sein: Is it possible for RSpec to expect change in two tables?. Sein Nachteil ist, dass man nur nach expliziten Änderungen von bekannten Werten zu bekannten Werten sucht.

Ich habe einig Pseudo-Code auf, wie ich glaube, ein besserer Matcher aussehen könnte:

expect { 
    click_button 'Save' 
}.to change_multiple { @user.reload }.with_expectations(
    name:    {from: 'donald', to: 'gustav'}, 
    updated_at:   {by: 4}, 
    great_field:  {by_at_leaset: 23}, 
    encrypted_password: true, # Must change 
    created_at:   false, # Must not change 
    some_other_field: nil # Doesn't matter, but want to denote here that this field exists 
) 

ich so das Grundgerüst des ChangeMultiple Matcher erstellt habe auch:

module RSpec 
    module Matchers 
    def change_multiple(receiver=nil, message=nil, &block) 
     BuiltIn::ChangeMultiple.new(receiver, message, &block) 
    end 

    module BuiltIn 
     class ChangeMultiple < Change 
     def with_expectations(expectations) 
      # What to do here? How do I add the expectations passed as argument? 
     end 
     end 
    end 
    end 
end 

Aber jetzt Ich erhalte diesen Fehler bereits:

Failure/Error: expect { 
    You must pass an argument rather than a block to use the provided matcher (nil), or the matcher must implement `supports_block_expectations?`. 
# ./spec/features/user/registration/edit_spec.rb:20:in `block (2 levels) in <top (required)>' 
# /Users/josh/.rvm/gems/[email protected]/gems/activesupport-4.2.0/lib/active_support/dependencies.rb:268:in `load' 
# /Users/josh/.rvm/gems/[email protected]/gems/activesupport-4.2.0/lib/active_support/dependencies.rb:268:in `block in load' 

Jede Hilfe bei der Erstellung thi S Custom Matcher wird sehr geschätzt.

Antwort

62

In RSpec 3 können Sie mehrere Bedingungen gleichzeitig einrichten (sodass die Einzelerwartungsregel nicht unterbrochen wird). Es würde aussehen wie etw:

expect { 
    click_button 'Save' 
    @user.reload 
}.to change { @user.name }.from('donald').to('gustav') 
.and change { @user.updated_at }.by(4) 
.and change { @user.great_field }.by_at_least(23} 
.and change { @user.encrypted_password } 

es jedoch keine vollständige Lösung ist - soweit meine Forschung ging es keine einfache Möglichkeit ist and_not noch zu tun. Ich bin mir auch unsicher über Ihre letzte Überprüfung (wenn es nicht wichtig ist, warum testen Sie es?). Natürlich sollten Sie in der Lage sein, es in Ihre custom matcher zu wickeln.

+4

, wenn Sie feststellen, dass mehrere Dinge erwarten wollen, * nicht * geändert, Verwenden Sie einfach '.and change {@etwas} .by (0)' –

+0

Können Sie ein zweites Beispiel mit allen Klammern hinzufügen? Ich bin schwer zu verstehen, welche Methoden verkettet sind –

4

Wenn Sie testen möchten, dass mehrere Datensätze nicht geändert wurden, können Sie einen Matcher mit RSpec::Matchers.define_negated_matcher invertieren. So fügen

RSpec::Matchers.define_negated_matcher :not_change, :change 

zum Anfang der Datei (oder auf Ihre rails_helper.rb) und dann können Sie Kette mit and:

expect{described_class.reorder}.to not_change{ruleset.reload.position}. 
    and not_change{simple_ruleset.reload.position}