ChatGPT解决这个技术问题 Extra ChatGPT

Ruby Rspec : Testing instance variables without adding an accessor to source

I'm trying to test the following method:

def unprocess_move(board, move)
  if move[0].instance_of?(Array)
    multi_move = @multi_move.pop(2).reverse
    multi_move.each do |single_move|
      unapply_move(board, single_move)
    end
  else
    board = unapply_move(board, move)
  end
  board
end

where I want to set the state for @multi_move, but I don't want to add an accessor just for testing. Is there a way to do so without the accessor? Thanks.


A
Aliaksei Kliuchnikau

You can use Object#instance_variable_get method to get value of any instance variable of the object like that:

class Foo 
  def initialize
    @foo = 5 # no accessor for that variable
  end 
end

foo = Foo.new
puts foo.instance_variable_get(:@foo)
#=> 5

And Object#instance_variable_set can be used to set instance variable values:

foo.instance_variable_set(:@foo, 12) 
puts foo.instance_variable_get(:@foo)
#=> 12

But I need to set it beforehand within my test. It doesn't have a value before I test it.
@steve_gallagher, take a look at the docs. There is instance_variable_set right next to instance_variable_get (added example and link to the docs to the answer).
Interesting. I didn't know you could just go right in and set and get any instance variable like that. I've seen alot of RSpec testing, though, and I've never seen those methods called. Seems like a non-standard way of handling what I would think would be a pretty typical situation. I'm not complaining, though, thanks for the answer.
@steve_gallagher, I think the reason why you haven't seen that before is that private state of an object is not what you should test in most cases. If you aim to test behavior and logic of some object you should test what it does, but not how it does. If you don't provide public access to some instance variable (like not defining getter for it in your case) there is no need for someone outside of the object to care about its state as long as the object behaves as it should. In your case maybe it's better to test the result rather then the fact that some instance variable was set.
Your explanation is very appreciated, looking at it now with a different perspective, I don't know why I didn't notice that before, clearly I need to refactor it so that the instance variable doesn't need to be set to prove the method works. Thanks, again.