2015-04-01 13 views
31

Chcę sprawdzić wiele zmian w modelu podczas przesyłania formularza w specyfikacji funkcji. Na przykład chcę się upewnić, że nazwa użytkownika została zmieniona z X na Y i że zaszyfrowane hasło zostało zmienione o dowolną wartość.RSpec: Spodziewana zmiana wielokrotna

Wiem, że są już pewne pytania na ten temat, ale nie znalazłem dla mnie odpowiedniej odpowiedzi. Najbardziej dokładna odpowiedź wydaje się być taka, jakmatcher Michaela Johnstona tutaj: Is it possible for RSpec to expect change in two tables?. Jego wadą jest to, że jeden sprawdza tylko wyraźne zmiany od znanych wartości do znanych wartości.

stworzyłem jakiś pseudo kod, w jaki myślę, że lepiej dopasowujący może wyglądać tak:

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 
) 

Mam również stworzył podstawowy szkielet ChangeMultiple dopasowującego takiego:

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 

ale teraz Otrzymuję już ten błąd:

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' 

Każda pomoc w utworzeniu s niestandardowy matcher jest bardzo ceniony.

Odpowiedz

62

W RSpec 3 można ustawić wiele warunków naraz (więc zasada pojedynczego oczekiwania nie jest zepsuta). to będzie wyglądać jak sth:

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 } 

To nie jest kompletnym rozwiązaniem, choć - o ile się tam moje badania nie jest łatwym sposobem na and_not jeszcze. Nie jestem również pewien twojego ostatniego sprawdzenia (jeśli to nie ma znaczenia, po co go testować?). Oczywiście powinieneś być w stanie zawinąć go w swoim custom matcher.

+4

jeśli chcesz oczekiwać, że wiele rzeczy * nie * zmieniło, po prostu użyj '.i zmień {@something} .by (0)' –

+0

Czy możesz dodać drugi przykład ze wszystkimi nawiasami? Trudno mi zrozumieć, które metody są powiązane –

4

Jeśli chcesz przetestować, że wiele rekordów nie zostało zmienionych, możesz zmienić odwzorowanie za pomocą RSpec::Matchers.define_negated_matcher. Więc dodać

RSpec::Matchers.define_negated_matcher :not_change, :change 

do początku pliku (lub do rails_helper.rb), a następnie można łańcuch używając and:

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