Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ruby-on-rails/56.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby on rails 如何使用FlexMock哈希匹配器验证数组值的一部分?_Ruby On Rails_Ruby_Unit Testing_Mocking - Fatal编程技术网

Ruby on rails 如何使用FlexMock哈希匹配器验证数组值的一部分?

Ruby on rails 如何使用FlexMock哈希匹配器验证数组值的一部分?,ruby-on-rails,ruby,unit-testing,mocking,Ruby On Rails,Ruby,Unit Testing,Mocking,我试图验证我的Rails代码是否调用ActiveRecord的all方法(对于find:all,all是语法糖),如下所示: records = Record.all :limit => RECORD_LIMIT, :offset => record_offset, :select => 'id', :conditions => [ 'record_type = ? AND content_score >=

我试图验证我的Rails代码是否调用ActiveRecord的all方法(对于find:all,all是语法糖),如下所示:

      records = Record.all
        :limit => RECORD_LIMIT, :offset => record_offset,
        :select => 'id',
        :conditions => [ 'record_type = ? AND content_score >= ?', 'user', min_content_score ],
        :order => 'content_score DESC'
mock.should_receive(:all).with FlexMock.hsh [ 'record_type = ? AND content_score >= ?', Object, Object ]
mock.should_receive( :all ).
  with( Flexmock.key( :conditions ) ).
  and_return []
在这个实例中,我关心的代码的唯一部分是:conditions参数,我只关心SQL代码段,而不关心绑定变量的实际值。我可以使用FlexMock哈希匹配器断言(至少)存在:conditions参数,如下所示:

mock.should_receive(:all).with FlexMock.hsh :conditions => []
mock.should_receive(:all).
  with( HashKeyMatcher.new( :conditions ) ).
  and_return []
但是,这只匹配:conditions参数的值为空数组的调用。我真正想要的是这样的东西:

      records = Record.all
        :limit => RECORD_LIMIT, :offset => record_offset,
        :select => 'id',
        :conditions => [ 'record_type = ? AND content_score >= ?', 'user', min_content_score ],
        :order => 'content_score DESC'
mock.should_receive(:all).with FlexMock.hsh [ 'record_type = ? AND content_score >= ?', Object, Object ]
mock.should_receive( :all ).
  with( Flexmock.key( :conditions ) ).
  and_return []
但不幸的是,正如irb所揭示的,“用户”和“对象”并不等同:

>> '' === Object

有什么好主意吗?嵌套匹配器是否可行?

解决此问题需要猴子修补FlexMock和一个对象,因此不适合心脏虚弱的人。:)

首先,monkey patch FlexMock::HashMatcher在期望对象而不是实际对象上调用==:

class FlexMock::HashMatcher
  def ===(target)
    @hash.all? { |k, v| v == target[k] }
  end
end
接下来,构造一个对象并重新定义其==方法:

conditions_matcher = Object.new
conditions_matcher.instance_eval do
  def ==(other)
    other.first == 'record_type = ? AND content_score >= ?'
  end
end
最后,设置您的FlexMock期望值:

mock.should_receive(:all).
    with(FlexMock.hsh(:conditions => conditions_matcher)).
    and_return []
这适用于以下所有调用:

Record.all :conditions => [ 'record_type = ? AND content_score >= ?' ]
Record.all :conditions => [ 'record_type = ? AND content_score >= ?', 'foo' ]
Record.all :conditions => [ 'record_type = ? AND content_score >= ?', 'foo', 5.0 ]

鲁比是个疯子,但在某种程度上是好的

鸭子出击这应该不是必要的。您可以非常轻松地定义自己的参数匹配器:

class HashKeyMatcher
  def initialize( key )
    @key = key
  end

  def ===( other )
    other.respond_to?( :keys ) && other.keys.include? @key
  end

  def inspect() "HashKeyMatcher( #{@key.inspect} )"; end
end
然后你就这样使用它:

mock.should_receive(:all).with FlexMock.hsh :conditions => []
mock.should_receive(:all).
  with( HashKeyMatcher.new( :conditions ) ).
  and_return []
将HashKeyMatcher放在可以从测试访问的地方

如果愿意,可以通过打开Flexmock类并添加新方法,以类似于其他Flexmock参数匹配器的方式使其可用:

class Flexmock
  def self.key( hash_key )
    HashKeyMatcher.new hash_key
  end
end
然后您可以这样编写测试:

      records = Record.all
        :limit => RECORD_LIMIT, :offset => record_offset,
        :select => 'id',
        :conditions => [ 'record_type = ? AND content_score >= ?', 'user', min_content_score ],
        :order => 'content_score DESC'
mock.should_receive(:all).with FlexMock.hsh [ 'record_type = ? AND content_score >= ?', Object, Object ]
mock.should_receive( :all ).
  with( Flexmock.key( :conditions ) ).
  and_return []

啊。。。源代码似乎表明我想要做的是不可能的:除非我可以重写right==方法。。。请继续关注。如果只将FlexMock::HashMatcher#===方法定义为“@hash.all?{k,v | v==target[k]}”,我对==的猴子补丁就可以了。也许是时候开公开课了。好吧,我比我疯狂的解决方案更喜欢这个。谢谢