自定义RSpec匹配器占用一个块

时间:2013-04-25 18:49:07

标签: ruby rspec

如何创建以下RSpec匹配器?

foo.bars.should incude_at_least_one {|bar| bar.id == 42 }

让我知道如果我重新发明轮子,但我也很想知道如何创建一个自定义匹配器。一些内置的匹配器可以做到,所以它是可能的。我试过这个:

RSpec::Matchers.define :incude_at_least_one do |expected|
  match do |actual|
    actual.each do |item|
      return true if yield(item)
    end
    false
  end
end

我试图在两个方面传递&block。我错过了一些简单的事情。

3 个答案:

答案 0 :(得分:1)

我开始使用Neil Slater的代码,然后开始工作:

class IncludeAtLeastOne
  def initialize(&block)
    @block = block
  end

  def matches?(actual)
    @actual = actual
    @actual.any? {|item| @block.call(item) }
  end

  def failure_message_for_should
    "expected #{@actual.inspect} to include at least one matching item, but it did not"
  end

  def failure_message_for_should_not
    "expected #{@actual.inspect} not to include at least one, but it did"
  end
end

def include_at_least_one(&block)
  IncludeAtLeastOne.new &block
end

答案 1 :(得分:0)

有关于将这样的匹配器添加到rspec的讨论。我不确定你的阻止问题,但你可以代表这个测试,而不是看起来优雅:

foo.bars.any?{|bar| bar.id == 42}.should be_true

可能比制作自定义匹配器更容易,如果您的测试类似于it "should include at least one foo matching the id"

,则应该可读

答案 2 :(得分:0)

RSpec DSL不会这样做,但你可以这样做:

class IncludeAtLeastOne
  def matches?(target)
    @target = target
    @target.any? do |item|
      yield( item )
    end
  end

  def failure_message_for_should
    "expected #{@target.inspect} to include at least one thing"
  end

  def failure_message_for_should_not
    "expected #{@target.inspect} not to include at least one"
  end
end

def include_at_least_one
  IncludeAtLeastOne.new
end

describe "foos" do
  it "should contain something interesting" do
    [1,2,3].should include_at_least_one { |x| x == 1 }
  end
end