Rspec Let Scoping

Rspec let scoping

I found what works for me:

   describe Connection do
it_behaves_like "any connection", new.connection
# new.connection: because we're in the class context
# and let creates method in the instance context,
# instantiate a instance of whatever we're in
end

Rspec let scoping with shared examples

Here in your example method re-defining has been done. When include_context 'a' has been executed then it defines let_example as a method which prints 'let_example a'. But when you include_context 'b' has been executed then redefines the method let_example which would effectively prints let_example 'b'.

When to use RSpec let()?

I always prefer let to an instance variable for a couple of reasons:

  • Instance variables spring into existence when referenced. This means that if you fat finger the spelling of the instance variable, a new one will be created and initialized to nil, which can lead to subtle bugs and false positives. Since let creates a method, you'll get a NameError when you misspell it, which I find preferable. It makes it easier to refactor specs, too.
  • A before(:each) hook will run before each example, even if the example doesn't use any of the instance variables defined in the hook. This isn't usually a big deal, but if the setup of the instance variable takes a long time, then you're wasting cycles. For the method defined by let, the initialization code only runs if the example calls it.
  • You can refactor from a local variable in an example directly into a let without changing the
    referencing syntax in the example. If you refactor to an instance variable, you have to change
    how you reference the object in the example (e.g. add an @).
  • This is a bit subjective, but as Mike Lewis pointed out, I think it makes the spec easier to read. I like the organization of defining all my dependent objects with let and keeping my it block nice and short.

A related link can be found here: http://www.betterspecs.org/#let

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

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)

Rspec - Using variable defined in a let statement in another let statement

let(:name1) { "#{testcase['Car']}_#{Time.now.round}" }

let(:car1) { { name1: name1, car_model: testcase['Toyota'] } }

let(:car2) { { name2: name1 } }

So name1 is also now a lazy variable to initialized when is called, if not for car1, then for car2.

If the Time.now is a problem, you can leave the value of name1 as testcase['Car'] and then just interpolate the value of Time.now.



Related Topics



Leave a reply



Submit