Some sweet, sweet Rspec syntax

This post assumes knowledge of Rspec, one of Ruby’s testing suites.

I’ve been using the let function in Rspec for several weeks now without fully understanding how it works.

The awesome Kevin Skoglund and his lynda.com course on Rspec had the answer for me. I may have watched some of it in the bath yesterday evening, after a Muay Thai training session — but that’s none of your business :D

Let(:it) { happen} (song by Tame Impala)

Let’s say that you had a before(:example) block that set up a new car before each example:

before(:example) do
@car = Car.new
end

What happens if one of your examples doesn’t even call car? This code block will still be run — not hugely expensive in terms of time, but it could be if you had 100s of tests with large before blocks.

It also doesn’t keep the car instance around — it reassigns that value each time.

It also requires us to go into our rspec code and add @ symbols to all our examples.

Skoglund argues that it would be much “slicker” if we could define a new method called car that is called each time car is used. By using the “upright pipes-equal” combo, if @car already exists Ruby will use that, otherwise it will get a new Car instance — this is called “memoisation”.

before(:context) do
def car
@car ||= Car.new
end
end

Whilst Skoglund doesn’t advise we actually use the above code, he gives this example because that is essentially what the let method is doing for us.

The let method creates a helper method that does the above for you, automatically doing the memoization. If @car doesn’t exist, it will create a new Car.

Let!!!!

If let has an exclamation mark after it, it signifies that it is “eager execution”.

Normally let is lazily executed — only executed when it is required (when car is used in the code). Not let!. This is executed on the spot.