How to set private instance variable used within a method test?

44,189

Solution 1

As you answered in your question the easiest way to set instance variable is with instance_eval method:

obj.instance_eval('@a = 1')

Another way is to use instance_variable_set:

obj.instance_variable_set(:@a, 1)

But I would not recommend to do this in your specs. Specs are all about testing behavior of an object and testing behaviour by breaking class encapsulation with instance_eval will make your tests more fragile and implementation dependent.

Alternative approach to object state isolation is to stub accessor methods:

class UnderTest
  attr_accessor :a

  def test_this
    do_something if a == 1
  end
end

#in your test
under_test = UnderTest.new
under_test.stub(:a).and_return(1)

Solution 2

Use instance_variable_set:

class SomeClass
  attr_reader :hello
  def initialize
    @hello = 5
  end
  # ...
end

a = SomeClass.new
a.hello    # => 5

a.instance_variable_set("@hello", 7)
a.hello    # => 7
Share:
44,189
Torbjörn
Author by

Torbjörn

Mathematician by training, coder by passion and employed as C++ developer by a German cancer diagnostics startup. I do love coding in modern C++ and Python.

Updated on July 09, 2022

Comments

  • Torbjörn
    Torbjörn almost 2 years

    Given a class with a couple of instance variables and some methods. Some instance variables are set accessible via attr_reader and attr_accessor. Thus the others are private.
    Some of the private instance variables get set within one of the instance methods and read/utilized within another method.

    For testing I'm using RSpec. As I'm still new to Ruby and want to get all things right, I defined my tests being rather fine-grained. Thus I've got one describe block for each instance method, which themselves are partitioned into a subset of contexts and its. General environmental preconditions are defined with before.

    However, when testing one of the methods, which is utilizing but not setting one of the private variables, I need to call the other method, which is setting this variable. This seems rather overweight and not modular for me.

    Is there a way of forcing a private instance variable to a certain value. Similar to "ripping out" the value of a private instance variable with Object::instance_eval(:var).