0

我想模拟一个对象,它可能会收到我不关心的任意数量的消息。我希望这个对象有一个默认答案,例如“真”,能够在重要的地方添加特定的方法和答案。是否可以在 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

如果读者对此功能的动机感兴趣,那么假设我不想挖掘并找出它可能接收到的所有可能消息,或者可能的消息集非常大或未知。

像这样的东西内置在 RSpec 中吗?

4

1 回答 1

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
于 2013-09-04T05:19:30.460 回答