以任何顺序匹配多个收益率

时间:2014-06-30 14:30:44

标签: ruby-on-rails ruby rspec iterator yield

我想使用rspec测试迭代器。在我看来,唯一可能的产量匹配器是yield_successive_args(根据https://www.relishapp.com/rspec/rspec-expectations/v/3-0/docs/built-in-matchers/yield-matchers)。其他匹配器仅用于单一屈服。

但如果屈服的顺序不是指定的,那么yield_successive_args就会失败。

是否有任何方法或很好的解决方法来测试以任何顺序产生的迭代器?

如下所示:

expect { |b| array.each(&b) }.to yield_multiple_args_in_any_order(1, 2, 3)

2 个答案:

答案 0 :(得分:1)

这是我为这个问题找到的匹配器,它相当简单,并且应该具有很高的效率。

require 'set'

RSpec::Matchers.define :yield_in_any_order do |*values|
  expected_yields = Set[*values]
  actual_yields = Set[]

  match do |blk|
    blk[->(x){ actual_yields << x }]    # ***
    expected_yields == actual_yields    # ***
  end

  failure_message do |actual|
    "expected to receive #{surface_descriptions_in expected_yields} "\
    "but #{surface_descriptions_in actual_yields} were yielded."
  end

  failure_message_when_negated do |actual|
    "expected not to have all of "\
    "#{surface_descriptions_in expected_yields} yielded."
  end

  def supports_block_expectations?
    true
  end
end

我用# ***突出显示包含大部分重要逻辑的行。这是一个非常简单的实现。

用法

只需将其放在spec/support/matchers/下的文件中,并确保从需要它的规格中获取该文件。大多数时候,人们只需添加这样一行:

Dir[File.dirname(__FILE__) + "/support/**/*.rb"].each {|f| require f}

到他们的spec_helper.rb,但是如果你有很多支持文件,并且它们并不是所有地方都需要的话,这可能会有点多,所以你可能只想把它包含在使用它的地方

然后,在规范本身中,用法就像任何其他产生匹配器的用法一样:

class Iterator
  def custom_iterator
    (1..10).to_a.shuffle.each { |x| yield x }
  end
end

describe "Matcher" do
  it "works" do
    iter = Iterator.new
    expect { |b| iter.custom_iterator(&b) }.to yield_in_any_order(*(1..10))
  end
end

答案 1 :(得分:0)

这可以使用一组数组交换在纯Ruby中解决:

array1 = [3, 2, 4]
array2 = [4, 3, 2]
expect(array1).to eq (array1 & array2)

# for an enumerator:
enumerator = array1.each
expect(enumerator.to_a).to eq (enumerator.to_a & array2)

交集(&)将返回两个集合中存在的项目,保持第一个参数的顺序。