使用RSpec双倍

时间:2015-11-30 11:14:45

标签: ruby rspec mocking

无法通过扩展其实例来更改RSpec双精度。

最小的例子

请注意,此处描述的示例只是一个最小的示例 来证明这个问题。原始类更复杂 需要调用(obj.extend(Something))的行为 无法改变。

规格

让我们先看看规范。 在下面的示例中,您可以看到我希望它看起来如何的规格:

require 'spec_helper'

RSpec.describe Modifier do
  subject(:modifier) { described_class.new(active) }

  describe "#apply_to(obj)" do
    subject(:obj) { instance_double(Foo, foo: "foo") }

    before { modifier.apply_to(obj) }

    context "when active" do
      let(:active) { true }
      its(:foo) { is_expected.to eq("extended-foo") }  # NOTE: This one will fail
    end

    context "when not active" do
      let(:active) { false }
      its(:foo) { is_expected.to eq("foo") }
    end
  end
end

不幸的是,这不起作用:(

Failures:

  1) Modifier#apply_to(obj) when active foo should eq "extended-foo"
     Failure/Error: its(:foo) { is_expected.to eq("extended-foo") }

       expected: "extended-foo"
            got: "foo"

class Foo
  attr_reader :foo

  def initialize(foo)
    @foo = foo
  end
end

改性剂

该类将通过扩展其实例方法来修改给定对象。

class Modifier
  def initialize(active)
    @active = active
  end

  # NOTE: This is the interesting method
  def apply_to(obj)
    return unless active?

    obj.extend(Extended)     # NOTE: And this is the interesting LOC
  end

  def active?
    @active
  end

  private

  attr_reader :active

  module Extended
    def foo
      "extended-#{super}"
    end
  end
end

更简单的例子

整个问题可以分解为以下代码片段:

module Bar
  def foo
    "bar"
  end
end

double = RSpec::Mocks::Double.new("Foo", foo: "foo")
obj = Object.new

double.extend(Bar)
obj.extend(Bar)

double.foo
# => "foo"

obj.foo
# => "bar"

结论

无法通过扩展其实例来改变RSpec双精度,这是预期的行为吗?

如果是这样,您如何为此处描述的示例创建可读的规范?

链接

1 个答案:

答案 0 :(得分:0)

如果规范知道它会占用extendend对象,为什么不期望extend调用呢?

expect(obj).to receive(:extend).and_return { class.new.extend(...) }