RSpec:期望改变多个

Jos*_*eim 65 rspec ruby-on-rails matcher

我想在功能规范中提交表单时检查模型中的许多更改.例如,我想确保用户名从X更改为Y,并且加密密码已更改为任何值.

我知道已经有一些问题,但我找不到合适的答案.最准确的答案似乎ChangeMultiple是迈克尔约翰斯顿的匹配器:RSpec有可能期望两个表的变化吗?.它的缺点是只检查从已知值到已知值的显式变化.

我创建了一些关于我认为更好的匹配器看起来如何的伪代码:

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
)
Run Code Online (Sandbox Code Playgroud)

我还创建了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
Run Code Online (Sandbox Code Playgroud)

但是现在我已经收到了这个错误:

 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/ruby-2.1.0@base/gems/activesupport-4.2.0/lib/active_support/dependencies.rb:268:in `load'
 # /Users/josh/.rvm/gems/ruby-2.1.0@base/gems/activesupport-4.2.0/lib/active_support/dependencies.rb:268:in `block in load'
Run Code Online (Sandbox Code Playgroud)

任何有关创建此自定义匹配器的帮助都非常感谢.

Bro*_*tse 143

在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 }
Run Code Online (Sandbox Code Playgroud)

这不是一个完整的解决方案 - 就我的研究而言,还没有简单的方法可做and_not.我也不确定你的最后一次检查(如果没关系,为什么要测试呢?).当然,您应该能够将其包装在自定义匹配器中.

  • 如果你想期望多个事物不被*改变,只需使用`.并改变{@something} .by(0)` (5认同)
  • 您可以添加第二个带有所有括号的示例吗?我很难理解哪些方法是链接的 (2认同)

Mat*_*nea 26

如果要测试多个记录未更改,可以使用反转匹配器RSpec::Matchers.define_negated_matcher.所以,添加

RSpec::Matchers.define_negated_matcher :not_change, :change
Run Code Online (Sandbox Code Playgroud)

到你的文件的顶部(或你的rails_helper.rb),然后你可以链接使用and:

expect{described_class.reorder}.to not_change{ruleset.reload.position}.
    and not_change{simple_ruleset.reload.position}
Run Code Online (Sandbox Code Playgroud)