DEV Community

Cover image for Building Tests in Ruby: RSpec Helper Methods and Hooks
Tori Crawford
Tori Crawford

Posted on • Edited on

Building Tests in Ruby: RSpec Helper Methods and Hooks

Two weeks ago I started this series with this post. I got a little side tracked last week and earlier this week due to receiving my first job offer in tech, but I’m trying to get back on track by writing this. This post is the second installment of this RSpec series and we will be covering a few really common Rspec helper methods and hooks: let, before, and after.

Before you start thinking “but what about include, match, raise_error, etc”, don’t you worry. I will be covering these expectations and matchers in the next installment of this series. I thought they deserved their own post as there are quite a few that I plan on covering. With that said, let’s go ahead and dive into these RSpec helper methods and hooks.

after

I’m going to do this a little backwards and talk about after first here. It’s a relatively easy concept to grasp, which is why I’m starting here and then working our way into the more complex ones.

after accepts an argument of all or each and executes whatever functionality you give it either after each test has completed or after all the tests have executed.

code showing after hooks

Take a moment and consider what order you think these would print out in before looking below this line!

answers to above code

Were you right?! If you were, YAY! If not, just take a moment and re-read the description above. Pay special attention to the italicized words and the words passed as arguments to each after statement.

let and before

In this section we are going to discuss the helper method let and the hook before. before is similar to after, as it can also accept the arguments all and each. The difference is that this hook type is excited either before all tests are executed or before each test is executed.

code showing before hooks

Again, let's see if you can guess the correct order of output!

answers of before hooks code

Now that we have that comparison out of the way I want to discuss some difficulties I had while learning to build RSpec tests. When I began writing tests, I hit a snag and I couldn’t figure out what was happening. It took me a while to realize that I was using the hook before instead of the helper method let. The big difference between these two is that let queries the database one time and saves the newly created object as a local variable, meanwhile using before to create a database query queries the database at the beginning of each test, which increases load time and slows down your tests.

side by side comparison of before and let

What I was doing wrong was that I was writing my tests expecting an attribute of the user to equal something specific, but I hadn’t included a before statement in that specific test, nor was I using before(:each) or before(:all). I kept receiving an error saying that the user did not exist. Can you guess why this is from what I’ve told you so far?

You are right if you’re thinking that before doesn’t save the object to a local variable, so it really didn’t exist within the test I was working on. It had only existed as an instance variable in the test I had used it previously. So, where it was applicable, I removed all the before methods and used let in its place, that way I only had to query my database one time and had a ready to use local variable for multiple tests.

Outside of the amount of times you query the database there is one more snag to using before. When a developer uses before, this database query has to be saved as an instance variable. At first this doesn’t seem to be problematic, but it could be. The reason for this is because in tests, instance variables “spring into existence” as nil if they weren’t previously defined. This means that if you have a typo in your variable, your code could possibly still work properly.

Let’s take a situation where you may be testing to see if a user is logged out. You’d expect the test to check if the user is logged out by testing if @user is equal to nil. If you accidentally typed @usr your test would still pass because @usr does equal nil, meanwhile you have no idea if @user is actually nil or not.

code showing non-error when using typo

If you were to accidentally misspell user while using let, you would receive a NameError error.

code showing error message when typo

To me, it seems as if using let to define variables available to use throughout your tests is the better and safer way to go. before does serve a purpose, such as performing tasks before a test as you can see in the example above, but I wouldn’t use it to query the database and define variables to use throughout your tests.

Final Thoughts

Now we’ve learned about a few of the common hooks and a very common helper method that are used when building RSpec tests! Please note that there are MANY more that could be discussed, so please feel free to google for more or take a look at my sources which name a few others as well.

While writing this post, I had an “ah-ha” moment and was able to fix a few different errors that I had been having for 2 weeks now in my project that I’m building alongside writing these posts. This is exactly why I love writing technical posts. I gain just as much knowledge and learn new things while researching and writing as y’all do from reading my posts. It’s always incredibly rewarding, so thank you all for continuing to read my stuff and motivating me to write weekly.

Note: This weeks cover image is brought to you from my travels to the small island of Utila, Honduras 2 years ago!

Sources

Before Vs Let
The Definitive RSpec Tutorial With Examples
RSpec - Hooks

Top comments (0)