Reputation: 22356
I have basically this setting in an RSpec test:
RSpec.describe Something do
describe '#something' do
let(:my_var) { 'some data' }
let(:my_object) { MyObject.new }
it 'example' do
my_object.instance_eval { @my_inst_var = my_var } # ERROR here
end
end
end
This results in
NameError: undefined local variable or method `myvar' for #MyObject:0x5d14e99e
I understand, that in the execution context of my_object
Ruby does not know how to deal with the "magic" of the let
construct in RSpec. I am aware that I could us "normal variables" here instead of let
, and I also can do (and this is how I am solving the problem at the moment):
# This works of course
it 'example' do
mv = my_var # Forces the let(:my_var) to be evaluated
my_object.instance_eval { @my_inst_var = mv }
end
Question: Is there a better way to do it, assuming that I do want to use let
and `instance_eval within the example?
Upvotes: 1
Views: 498
Reputation: 114248
Use instance_exec
instead – it allows you to pass arguments into the block's scope:
my_object.instance_exec(my_var) { |v| @my_inst_var = v }
Alternatively, you could set the instance variable via instance_variable_set
:
my_object.instance_variable_set(:@my_inst_var, my_var)
Although both of the above work, altering the object's state that way can lead to brittle tests. You should consider changing the object so it becomes easier to test. (add a setter or pass the value upon initialization)
Upvotes: 1
Reputation: 31
There are different ways to do this. Using instance_eval isn't high on my list. If an attr_accessor would make sense you should go that way for sure:
class Something
attr_accessor :my_inst_var
end
it 'example' do
my_object.my_inst_var = my_var
end
If you don't want to pollute your objects public methods I would consider the following option much cleaner than instance_eval.
it 'example' do
my_object.instance_variable_set :@my_instance_var, my_var
end
Upvotes: 1