webentwicklung-frage-antwort-db.com.de

RSpec: Erwarten Sie mehrere Änderungen

Ich möchte beim Senden eines Formulars in einer Feature-Spezifikation nach vielen Änderungen in einem Modell suchen. Ich möchte zum Beispiel sicherstellen, dass der Benutzername von X in Y geändert wurde und dass das verschlüsselte Kennwort durch einen beliebigen Wert geändert wurde.

Ich weiß, es gibt bereits einige Fragen dazu, aber ich habe keine passende Antwort für mich gefunden. Die genaueste Antwort scheint der ChangeMultiple-Matcher von Michael Johnston hier zu sein: Kann RSpec in zwei Tabellen Änderungen erwarten? . Der Nachteil ist, dass nur explizite Änderungen von bekannten Werten zu bekannten Werten geprüft werden.

Ich habe einen Pseudo-Code erstellt, wie ich denke, dass 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 habe auch das Grundgerüst des ChangeMultiple-Matchers so erstellt:

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 bekomme ich schon diesen Fehler:

 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 beim Erstellen dieses benutzerdefinierten Matchers wird sehr geschätzt.

51
Joshua Muheim

In RSpec 3 können Sie mehrere Bedingungen gleichzeitig einrichten (damit die Regel für eine einzelne Erwartung nicht verletzt wird). Es würde wie folgt aussehen:

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 ist jedoch keine vollständige Lösung - soweit es meine Forschung betrifft, gibt es noch keine einfache Möglichkeit, and_not zu tun. Ich bin mir auch nicht sicher, ob Sie Ihre letzte Überprüfung durchgeführt haben (wenn es nicht wichtig ist, warum testen Sie es?). Natürlich sollten Sie es in Ihren custom matcher packen können.

112
BroiSatse

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

RSpec::Matchers.define_negated_matcher :not_change, :change

an den Anfang Ihrer Datei (oder zu Ihrem Rails_helper.rb) und dann können Sie die Kette mit and ketten:

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

Die akzeptierte Antwort ist nicht 100% korrekt, da die full Compound Matcher-Unterstützung für change {} In RSpec Version 3.1.0 hinzugefügt wurde. Wenn Sie versuchen, den in der akzeptierten Antwort angegebenen Code mit der RSpec-Version 3.0 auszuführen, wird eine Fehlermeldung angezeigt.

Um zusammengesetzte Matcher mit change {} Zu verwenden, gibt es zwei Möglichkeiten.

  • Erstens müssen Sie mindestens RSpec Version 3.1.0 haben.
  • Zweitens müssen Sie der Klasse def supports_block_expectations?; true; endRSpec::Matchers::BuiltIn::Compound Hinzufügen, indem Sie sie entweder patchen oder die lokale Kopie des Edelsteins direkt bearbeiten. Ein wichtiger Hinweis: Diese Methode entspricht nicht der ersten, der Block expect {} Wird auf diese Weise mehrmals ausgeführt!

Die Pull-Anforderung, die die vollständige Unterstützung der Compound-Matcher-Funktionalität hinzugefügt hat, ist hier .

1
Foo Bar Zoo

Die Antwort von BroiSatse ist die beste, aber wenn Sie RSpec 2 verwenden (oder komplexere Matcher wie .should_not haben), funktioniert diese Methode auch:

lambda {
  lambda {
    lambda {
      lambda {
        click_button 'Save'
        @user.reload
      }.should change {@user.name}.from('donald').to('gustav')
    }.should change {@user.updated_at}.by(4)
  }.should change {@user.great_field}.by_at_least(23}
}.should change {@user.encrypted_password}
0
Zack Morris