Stubbing instance variables in RSpec 3.2
I think this is not a correct practice. Rspec should be testing the interface behaviour of classes, not the internal implementation.
As you are not using accessor, you can use #instance_variable_set
& #instance_variable_get
to manipulate and get the instance variable.
Getting and Setting are like follows:
@a.instance_variable_set(:@x, 5)
@a.instance_variable_get(:@x)
#=> 5
In your code:
@a.instance_variable_set(:@x, 5)
expect(@a.add(8)).to eq(13)
user2490003
Updated on June 26, 2022Comments
-
user2490003 almost 2 years
I'm using RSpec 3.2 in Rails and wondering how I can stub instance variables if they are not publicly made accessible by a getter method (e.g. using
attr_accessor
or similar).Consider the simple example below -
require 'rails_helper' class A def initialize @x = 3 end def add(n) sum = @x + n puts "Sum is #{sum}" sum end end RSpec.describe A do before(:all) do @a = A.new end it 'computes the sum correctly' do # For this test I want to stub the value of @x and return 5 allow(@a).to receive(:x) { 5 } # 5 + 8 should return 13 expect(@a.add(8)).to eq(13) end end
Trying to stub
@x
is not possible in this scenario as the class never never receives a message or method call forx
. The RSpec output confirms this -Failures: 1) A computes the sum correctly Failure/Error: allow(@a).to receive(:@x) { 5 } #<A:0x007fe6e66ab8d0 @x=3> does not implement: @x # ./spec/unit/test_spec.rb:25:in `block (2 levels) in <top (required)>'
I could work around this by making the instance variable
@x
accessible (attr_accesssor :x
) and replacing the call to@x
withself.x
, but that seems hacky and may not be possible in my more complex implementation.Is there a better way to stub this?
Thanks!