【问题标题】:Ruby + Rspec + OpenStruct weird behaviorRuby + Rspec + OpenStruct 奇怪的行为
【发布时间】:2014-10-02 09:23:09
【问题描述】:

所以我在测试 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

【问题讨论】:

  • 当我运行你的代码时,我得到Failure/Error: expect(Bar).to receive(:find).and_return(foo) (<Bar (class)>).find(any args) expected: 1 time with any arguments received: 0 times with any arguments

标签: ruby rspec rspec3


【解决方案1】:

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

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

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

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

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

其他解决方案是猴子修补 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

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

更多信息:Doubles and dynamic classess

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-25
    • 2019-06-24
    相关资源
    最近更新 更多