是否可以使用默认响应的rspec double?

时间:2013-09-03 23:10:44

标签: ruby rspec

我想模拟一个可能收到任何我不关心的消息的对象。我希望这个对象有一个默认的答案,比如'true',能够添加特定的方法和答案。是否可以在RSpec中执行此操作?我想要的是这样的:

obj = default_double(default: true, widget_count: 5)
obj.foobar.should == true
obj.widget_count.should == 5

如果我可以传入一个lambda或proc作为返回值并让default_double返回该lambda的评估,那就太好了。如果在测试的上下文中评估proc或lambda,并且可以访问示例中可用的变量,那将是非常好的。

因此,如果添加了上述功能,我们可能会有类似的内容:

@widgets = WidgetContainer.new
@widgets.widget_count = 5
obj = default_double(default: true, widget_count: lambda { @widgets.widget_count })
obj.foobar.should == true
obj.widget_count.should == 5

如果这个功能的动机对读者来说很有意思,那么让我们假设我不想挖掘并找出它可能收到的所有可能的消息,或者可能的消息集非常大或未知。 / p>

RSpec内置了这样的内容吗?

1 个答案:

答案 0 :(得分:0)

好的,我会小心翼翼地回答这个问题:

我相信RSpec 具有内置的模拟功能,它将接收任意消息并返回默认值。但是,它允许您将返回值指定为块,与Ruby的method_missing功能一起,应该允许您相当容易地构造上面描述的default_double方法。

虽然它可以从一些重构中获益,但是通过上面的例子,这是一个切入点:

require 'spec_helper'

def default_double(args)
  object = Object.new
  args.each do |key, value|
    if key == :default
      object.define_singleton_method(:method_missing) { |method, *args, &block| value }
    elsif Proc === value
      expect(object).to receive(key) do value.call end
    else expect(object).to receive(key).and_return(value)
    end
  end
  object
end

class WidgetContainer
  attr_accessor :widget_count
end

describe "default_double test" do
  it "should pass" do
    @widgets = WidgetContainer.new
    @widgets.widget_count = 5
    obj = default_double(default: true, widget_count: lambda { @widgets.widget_count })
    obj.foobar.should == true
    obj.widget_count.should == 5
  end
end