LMCMLJ LMCMLJ - 2 months ago 13
Ruby Question

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

I have an issue I have been whacking my head against for hours now, and neither I nor anyone I have asked has been able to come up with a suitable answer.

Essentially, I am writing a method that allows me to edit an instance variable of another method. I have multiple ways of doing this, however my issue is with writing the test for this method. I have tried many different double types, however as they are immutable and do not store states, I did not manage to find a way to make it work.

Here is the class whose

working
variable is changed:

class MyClass
attr_writer :working

def working?
@working
end
end


Here is the class and method that change it:

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


(The actual class is much larger, but I have only included a generalised version of the method in question. I can put all of the specific code up in a gist if it would help)

So I need a way to test that
makes_work
does in fact accept the array of objects to be changed, changes them and appends them to
array_of_fixed_objects
. What would be the best way of testing this in a containerised way, without requiring MyClass?

My last attempt was using spies to see what methods were called on my dummy instance, however a range of failures, depending on what I did. Here is the most recent test I wrote:

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


This currently throws the error:

undefined method to_sym for true:TrueClass


Many thanks for any help! I apologise if some formatting/ info is a little bit messed up, I am still pretty new to this whole stackoverflow thing!

Answer

I think the problem is have_received(working = true), it should be have_received(:working=).with(true)

Edit:

Examples of using have_received


This works for me

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
Comments