Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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).

like image 513
Torbjörn Avatar asked Jan 27 '12 18:01

Torbjörn


People also ask

How do you access a private variable in a test class?

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.

Can instance variables be declared within methods?

Instance variables are declared inside a class but not within a method.

Can a private variable be accessed from a method?

A somewhat more correct statement would be "... private variables can be accessed by any method (or initializer) defined in the same type".

How do you create an instance variable inside a method?

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.


1 Answers

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) 
like image 77
Aliaksei Kliuchnikau Avatar answered Sep 23 '22 18:09

Aliaksei Kliuchnikau