user1934428
user1934428

Reputation: 22356

RSpec: Accessing a `let` definition from within a block in an example

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

Answers (2)

Stefan
Stefan

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

Stev-0
Stev-0

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

Related Questions