Rails API Testing or “You’ve been doing it wrong”

For the last several years I’ve been developing Ruby on Rails applications.  Nothing fancy, and most of them just failed projects that didn’t go anywhere.  During all this time I’ve trolled documentation on testing the app, saying “That would be nice to do one day”, but I’ve finally had enough and I want to change my evil ways. I’m going to start writing test cases with my applications.

To start with, I’m testing my API.  I didn’t even know where to start.  I watched a Railscasts episode where the legendary Ryan Bates talks about how he tests.  There were some great comments in there about all these additional plugins.  It seemed pretty overwhelming to me at first and there was quite a learning curve.  So I wanted to write some of this down in case there was someone out there like me who was going to start down the path of correcting the error of there ways before 2015 hits.

Basic Rails Testing

The first thing to check was the guide.  Rails has great documentation!

I ran:

Just to see if I would get any output.  After all, Ruby generates this for you automatically right?  Low and behold I got a failure!

Well, first I was missing the test environment, so I put that in the config/database.yml.  Easy problem to solve!

Next, my welcome controller gave me errors:

Ok, I already like this.  Looks like I need to intiate my test database?

Turns out that Devise is the culprit.  A quick trip to StackOverflow solves the problem.  I fixed it like they said. Then I ran into another one with Devise that I added to my test/test_helper.rb file.   Its so nice to go over roads that other people have traveled!

Running my test:

And I finally got tests to work!  Yay!  It looks like I’m doing it right.

From here, I looked to test other API calls, but all the documentation said that I should probably start looking at rspec.  Apparently, that’s how the cool kids are doing it.  (Or were doing it at some point when they wrote how to do it).  So after running rake test, that was the last testing I did with the distributed rails testing.

RSpec

This is the latest hotness in testing that I could find in my research.  Pretty much everybody seems to be using it.  I edited my Gemfile and added rspec-rails.  I also finally started grouping things so I wouldn’t install these unnecessary gems on my production servers.  Spoiler alert:  My completed Gemfile looks like the below:

As you can see, I added a few more gems after rspec-rails, but I’ll get into those in a second.

After doing bundle install I ran:

Now to test we run

bundle exec rspec

Ok, no tests to do yet!  Now to get to work!

Factory Girl & FFaker and other setup

The next step was to put Factory Girl.  Once again, Ryan Bates explains why Factory Girl is preferred over Fixtures.  I went back and added that to my Gemfile along with ffaker because I saw some cool things in that gem.  (The one thing not cool about ffaker was the documentation, but the code was easy enough to read.

Next, I modified config/application as specified in this blog entry.

I also had to add these modules into the rest of the environment.  I changed the spec/rails_helper.rb to have the below.  Everything else stayed the same:

Then I added the directory:

mkdir spec/support

I added the file  spec/support/devise.rb

as well as the file  spec/support/factory_girl.rb

That has all my extra libraries used for my tests.

Lastly, I setup the test database

rake db:test:prepare

A basic Tests

Now to set up some tests.  I thought it best to start off simple with a static page:

rails g rspec:controller welcome

This is the root of the homepage.  Following the documentation, I added some simple tests for the welcome page:

I ran bundle exec rspec  and it worked.  (Though not at first, as I had to figure out how to configure everything like I set up above. )

Testing User Model

rails generate rspec:model user

Since I already have a user model.  The list of spec modules to add are listed here.

Since we have a model we are testing, we need to generate the fixture for it.  Here’s how I made it work with my Devise implementation:

spec/factories/user.rb

The part that was most important that stumped me for a while was not putting the { } around Faker::Internet.email.  Since my tests tests for unique emails, it kept failing.  Putting the {} around Faker::Internet.email made sure it was unique on each call.

There’s a lot of documentation on cleaning up the database by using the database_cleaner gem.  I’m not using it right now.  ffaker generates all kinds of new things for me, so I don’t worry about it.  I suppose that the database would need to be initialized though from time to time.

This could be accomplished with:

Next I added the user model test

spec/models/user_spec.rb

This uses the shoulda-matches gem quite heavily and seems to be a good start to testing my user model.  Unit test check!

 Testing the API Controller

Next, I wanted to check the API for when users authenticate.  The way my API works (and the way I assume most work this way) is that the user will send a username (or email) and password and from that the application will send back an API token.  This makes subsequent calls stateless.  So I’ll test my session login  controller:

rails g rspec:controller api/v1/sessions

 I was happy to see it created  spec/controllers/api/v1/sessions_controller_spec.rb  just like how I have my API!

Here’s the first version of my working sessions_controller_spec.rb file:

Running this test:

Wow!  I feel like a real hipster programmer now!  Testing!

More Tests

This is just the beginning.  I am now a convert and subscribe to the theory that you should spend about half of your time writing test cases.  It pays off in the long run.  I have more to go, but from now on with each line of code I write I’ll be writing test cases.  It seems that I still have a lot of catching up to do with the current system.