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

How to test a class method that modifies an attribute of another class in a containerised way rspec

我有一个问题已经困扰我好几个小时了,我和我问过的任何人都无法给出合适的答案。

本质上,我正在编写一个允许我编辑另一个方法的实例变量的方法。我有多种方法可以做到这一点,但我的问题是为此方法编写测试。我已经尝试了许多不同的双精度类型,但是由于它们是不可变的并且不存储状态,所以我没有找到一种方法来使其工作。

这里是 class,其 working 变量被更改:

class MyClass
  attr_writer :working

  def working?
    @working
  end
end

这里是 class 和改变它的方法:

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

(实际的 class 要大得多,但我只包含了所讨论方法的通用版本。如果有帮助,我可以将所有具体代码放在要点中)

所以我需要一种方法来测试 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

非常感谢您的帮助!如果某些格式/信息有点混乱,我深表歉意,我对整个 Whosebug 还是很陌生!

我觉得问题是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

如果您只想避免存根,可以使用 OpenStruct 的实例而不是双精度实例:

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