如何测试以容器化方式rspec修改另一个类的属性的类方法

时间:2016-09-29 21:59:31

标签: ruby rspec tdd bdd

我有一个问题,我现在已经打了几个小时,我和我所问过的任何人都没有能够找到合适的答案。

基本上,我正在编写一个允许我编辑另一个方法的实例变量的方法。我有多种方法可以做到这一点,但我的问题是编写此方法的测试。我尝试过很多不同的双重类型,但由于它们是不可变的并且不存储状态,所以我没有找到办法让它工作。

以下是working变量更改的类:

class MyClass
  attr_writer :working

  def working?
    @working
  end
end

以下是更改它的类和方法:

class OtherClass
  def makes_work
    @ary_of_instances_of_MyClass_to_fix.map do |x|
      x.working = true
      @ary_of_fixed_objects << x
    end
  end
end

(实际的类要大得多,但我只包含了相关方法的通用版本。如果有帮助,我可以将所有特定代码放在一个要点中)

所以我需要一种方法来测试makes_work实际上是否接受要更改的对象数组,更改它们并将它们附加到array_of_fixed_objects。在不需要MyClass的情况下,以容器化的方式测试它的最佳方法是什么?

我的最后一次尝试是使用间谍来查看我的虚拟实例上调用了哪些方法,但是一系列失败,取决于我所做的。这是我写的最新测试:

describe '#make_work' do
  it 'returns array of working instances' do
    test_obj = spy('test_obj')
    subject.ary_of_instances_of_MyClass_to_fix = [test_obj]
    subject.makes_work
    expect(test_obj).to have_received(working = true)
  end
end

目前引发错误:

undefined method to_sym for true:TrueClass

非常感谢您的帮助!我很抱歉,如果某些格式/信息有点搞砸了,我仍然对这整个stackoverflow事情都很陌生!

2 个答案:

答案 0 :(得分:1)

我认为问题是have_received(working = true),应该是have_received(:working=).with(true)

编辑:

使用have_received

的示例

这对我有用

class MyClass
  attr_writer :working

  def working?
    @working
  end
end

class OtherClass
  attr_writer :ary_of_instances_of_MyClass_to_fix

  def initialize
    @ary_of_fixed_objects = []
  end
  def makes_work
    @ary_of_instances_of_MyClass_to_fix.map do |x|
      x.working = true
      @ary_of_fixed_objects << x
    end
  end
end

describe '#make_work' do
  subject { OtherClass.new }
  it 'returns array of working instances' do
    test_obj = spy('test_obj')
    subject.ary_of_instances_of_MyClass_to_fix = [test_obj]
    subject.makes_work
    expect(test_obj).to have_received(:working=).with(true)
  end
end

答案 1 :(得分:0)

如果你宁愿避免存根,你可以使用OpenStruct的实例而不是double:

class OtherClass
  attr_writer :ary_of_instances_of_MyClass_to_fix

  def initialize
    @ary_of_instances_of_MyClass_to_fix, @ary_of_fixed_objects = [], []
  end

  def makes_work
    @ary_of_instances_of_MyClass_to_fix.map do |x|
      x.working = true
      @ary_of_fixed_objects << x
    end
    @ary_of_fixed_objects
  end
end

require 'ostruct'

RSpec.describe "#makes_work" do
  describe "given an array" do
    let(:array) { [OpenStruct.new(working: nil)] }

    subject { OtherClass.new }

    before do
      subject.ary_of_instances_of_MyClass_to_fix = array
    end

    it "sets the 'working' attribute for each element" do
      expect(array.map(&:working)).to eq [nil]
      subject.makes_work
      expect(array.map(&:working)).to eq [true]
    end
  end
end