期待RSpec中的Lambdas

时间:2017-07-23 14:20:21

标签: ruby unit-testing testing lambda rspec

我有一个简单的课程:

ProposalsList

我试图像这样测试它:

class Maybe
  def initialize(value, maybe_klass = Maybe)
    @value = value
    @maybe_klass = maybe_klass
  end

  attr_reader :value

  def map(function)
    return self if value.nil?
    return maybe_klass.new(compose(value, function)) if value.is_a? Proc
    maybe_klass.new(function.curry.call(*value))
  end

  private

  attr_reader :maybe_klass

  def compose(f, g)
    lambda { |*args| f.call(g.call(*args))  }
  end
end

此测试不起作用 - it 'creates a new wrapped function that does both of the functions combined' do maybe_double = double Maybe add_four = ->(x) { x + 4 } maybe = Maybe.new(add_four, maybe_double) composed_lambda = ->(*args) { maybe.value.call(add_four.call(*args)) } expect(maybe_double).to receive(:new).with(composed_lambda) maybe.map(add_four) end

我认为组合的lambda在我需要它之前正在进行评估,但我不确定。我应该期望用双undefined method '+' for #<Proc:0x007fdd0b269e78>方法调用什么?这甚至是接近测试这门课程的正确方法吗?我觉得我用initialize变量过分模仿班级内部,但我不确定还有什么可以期待。

另外,因为该函数返回了我们正在测试的类的新实例,所以不可能存根整个类 - 我们最终会尝试存根被测系统。

2 个答案:

答案 0 :(得分:2)

看来,您拥有正确的代码,但您希望rspec以不同的方式工作。这是issue about it

rspec使用===来验证期望值,但在ruby中,当您在lambdas上使用===运算符时,会调用lambdas。因此,当您将lambda传递给receive(:new).with方法时,rspec会使用Maybe#new方法接收的参数调用此lambda。

对于您的情况,我建议您使用这个很酷的功能进行测试:

it 'creates a new wrapped function that does both of the functions combined' do
  maybe_double = double Maybe
  add_four = ->(x) { x + 4 }
  maybe = Maybe.new(add_four, maybe_double)
  expect(maybe_double).to receive(:new).with(lambda { |composed_lambda|
    expect(composed_lambda.(4)).to eq 12
  )
  maybe.map(add_four)
end

因此,您将验证Maybe#new收到的lambda是一个组合lambda并将值应用于该值。这是因为你不能比较两个lambda,直到你打电话给他们。

希望它有所帮助。

答案 1 :(得分:1)

作为解决方法,您可以使用it范围内的变量

it do
    calls1  = 0
    calls2  = 0
    lambda1 = ->(x) { calls1 += x }
    lambda2 = ->(y) { calls2 += y }

    maybe = Maybe.new(lambda1, Maybe)

    maybe.map(lambda2).value.call(1)
    expect(calls1).to eq(1)
    expect(calls2).to eq(1)
end

并不完美,但至少测试了lambda执行。