0

所以我在测试 ruby​​ 类时遇到了这种奇怪的行为。顺便说一下,我正在使用 rspec 3 对其进行测试。

Foo类有一个方法'fetch_object',它从类Bar调用'find'方法来检索一个对象,然后从获取的对象中调用'fail'方法。

当我期望接收方法“失败”一次但没有接收到方法时,就会发生所谓的奇怪行为,但是如果我将方法名称更改为“失败”,它就像一个魅力:S

这是戏剧:

require 'ostruct'

class Foo

  def fetch_object
    foobar = Bar.find
    foobar.fail
  end

end

class Bar

  def self.find
    OpenStruct.new(name: 'Foo Bar')
  end

end

describe Foo do

  subject { Foo.new }

  let(:foo) { OpenStruct.new() }

  before do
    expect(Bar).to receive(:find).and_return(foo)
  end

  it 'fetch object with name' do
    expect(foo).to receive(:fail)
    subject.fetch_object
  end

end
4

1 回答 1

2

我怀疑这是因为您对对象设置了期望,该行为取决于method_missingOpenStruct)。

出于这个原因,我不希望它作为模拟,我会使用常规模拟(并且规范会通过):

let(:foo) { double('foobar') }

您在这里进行测试,如果返回的对象(Bar.find 的结果)将收到预期的消息,而无需进入实现细节。

对像 ostruct 这样的动态类设置期望可能会导致奇怪的结果。似乎在某个时候Kernel#fail调用了一个方法,因此,将名称更改为faill或任何其他尚未被内核“采用”的名称都会使其工作。

其他解决方案是monkeypatching OpenStruct 以避免method_missing被称为:

class OpenStruct
  def fail
    true
  end
end

class Foo

  def fetch_object
    foobar = Bar.find
    foobar.fail
  end

end

class Bar

  def self.find
    OpenStruct.new(name: 'Foo Bar')
  end

end

describe Foo do

  subject { Foo.new }

  let(:foo) { OpenStruct.new }

  before do
    expect(Bar).to receive(:find).and_return(foo)
  end

  it 'fetch object with name' do
    expect(foo).to receive(:fail)
    subject.fetch_object
  end

end

但我不知道你为什么要这样做;)

更多信息:双打和动态课程

于 2014-10-02T01:23:09.507 回答