2015-04-01 31 views
31

我想在功能規格中提交表單時檢查模型中的許多更改。例如,我想確保用戶名已從X更改爲Y,並且加密密碼已被任何值更改。RSpec:預計會更改多個

我知道那裏已經有一些問題了,但是我沒有爲我找到合適的答案。最準確的答案看起來像邁克爾約翰斯頓在這裏的ChangeMultiple匹配器:Is it possible for RSpec to expect change in two tables?。它的缺點是隻能檢查從已知值到已知值的顯式變化。

我創建了我是怎麼想的更好的匹配可能看起來像一些僞代碼:

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 
) 

我也創建了ChangeMultiple匹配的這樣的基本骨架:

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 

但現在我已經得到這個錯誤:

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' 

任何幫助創造thi我們非常感謝他們的定製匹配器。

回答

62

在RSpec 3中,您可以一次設置多個條件(因此單個期望規則不會被破壞)。它看起來像某事:

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 } 

這不是一個完整的解決方案,但 - 據我的研究就沒有簡單的方法來做到and_not呢。我也不確定你的最後一張支票(如果沒關係,爲什麼要測試它?)。當然,你應該能夠把它包裝在你的custom matcher

+4

如果你想指望多事情*不*改變,只需使用'.and更改{@something} .by(0)' – 2017-04-14 13:32:15

+0

您可以使用所有括號添加第二個示例嗎?我很難理解哪些方法是鏈接的 – 2017-06-11 10:31:43

4

如果您想要測試多個記錄未被更改,您可以使用RSpec::Matchers.define_negated_matcher來反轉匹配器。所以,加

RSpec::Matchers.define_negated_matcher :not_change, :change 

到文件的頂部(或您rails_helper.rb),然後你可以鏈使用and

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