我有一个简单的课程:
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
变量过分模仿班级内部,但我不确定还有什么可以期待。
另外,因为该函数返回了我们正在测试的类的新实例,所以不可能存根整个类 - 我们最终会尝试存根被测系统。
答案 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执行。