5

如何创建以下 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在两个级别上通过。我错过了一些简单的东西。

4

3 回答 3

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
于 2013-04-25T20:23:25.393 回答
0

已经讨论过将这样的匹配器添加到 rspec。我不确定你的块问题,但你可以用看起来不那么优雅的方式来表示这个测试:

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

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

于 2013-04-25T19:26:09.327 回答
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
于 2013-04-25T19:31:52.707 回答