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:
Before you start thinking “but what about
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.
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
each and executes whatever functionality you give it either after each test has completed or after all the tests have executed.
Take a moment and consider what order you think these would print out in before looking below this line!
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
In this section we are going to discuss the helper method
let and the hook
before is similar to
after, as it can also accept the arguments
each. The difference is that this hook type is excited either before all tests are executed or before each test is executed.
Again, let's see if you can guess the correct order of output!
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.
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(: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.
If you were to accidentally misspell
user while using
let, you would receive a
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.
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!