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 context
s and it
s. 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)
.
Use the TestVisible annotation to allow test methods to access private or protected members of another class outside the test class. These members include methods, member variables, and inner classes. This annotation enables a more permissive access level for running tests only.
Instance variables are declared inside a class but not within a method.
A somewhat more correct statement would be "... private variables can be accessed by any method (or initializer) defined in the same type".
Instance variables are created when an object is created with the use of the keyword 'new' and destroyed when the object is destroyed. Instance variables hold values that must be referenced by more than one method, constructor or block, or essential parts of an object's state that must be present throughout the class.
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)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With