2015-04-01 51 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}