I put together several API tests.  Here’s the project on Github.com:

The project has three Cucumber features (under the features directory) that talk with a public API.

For the purpose of this test I’m using Rotten Tomatoes public API.  They have a nice JSON response to parse and utilize for these examples.

Example 1: /features/movie_json_smoke.feature

The first feature is a smoke test it basically validates the json itself.  The idea here is: We know what we expect to return in the JSON, we verify that the categories and sub categories are intact and no changes have occurred. This is useful, if a change to the service was made, but the overall structure of the JSON should remain the same.  Just kick off this test, and it validates the JSON structure.

Here’s how I did it in cucumber:
from here we have the Cucumber test itself.  I build the test out as a Scenario Outline, this allows me to utilize the data tables.  When I get to the “Then”, I pass in a parameter from the table, like this:

Then the response should have  the  expected
The category parameter matches the data table, which has a column header “category” – every element under that column in the table is passed into the Then statement.
The actual code is in the step definition:
it’s here that I grab the parameters coming form the table / test and I pass them into the relevant spots.  
Here’s an example:
Then /^the response should have the (.*) expected$/ do |category|
  @mquery[#{category}].should be_true
First, notice the (.*), that is the placeholder for the variable in the test . Second, the argument I’m grabbing |category| is coming from the test. It takes the Category value (from the data table in the test) and passes it through here.
The next line of code reads @mquery (that’s the instance variable) [“#{category}”].should be_true
So this is the way ruby picks up the JSON objects [‘category’][‘subcategory’] But since we’re passing in a dynamic parameter here, we need double quotes. so [“#{Category}”] (the #{category} will be replaced with the value in the data table.
The .should be_true tripped me up. I kept trying == !nil and .should == !nil, nothing worked until I found it should be done like this .should be_true. This validates that the JSON element the method is attached to is present.
 At this point, I just iterate through each parameter in their JSON returned.  I go through each category and subcategory and make sure that it’s all there.  

I figure that’s a good smoke test.  If I worked at RT, and some dev committed some code to their service/api, I could just run this and quickly see that json categories are still present.  

Example 2: movielookup_data_validation.feature

In this test, I’m treating a data table in the test as the source of truth.  This could be a database, but I’m using a data table with Cucumber’s Scenario Outline.  This time, I’ve added several columns.  I’m verifying the mpaa_rating and the profile image stored at Rotten Tomatoes.   

The code for verifying this is similar in concept to what I did previously:

I go through several movies… passed through, like this:

Given /^the API is queried for (.*)$/ do |title|

  @mquery = JSON.parse(open("http://api.rottentomatoes.com/api/public/v1.0/movies.json?apikey=jc7eaxjfpemb2uz7qsrudnsq&q=#{title}&page_limit=1").read)


The argument is passed through and is passed through to the API URI and grabs that movie’s details which are then verified
Notice that the main difference then before is this code:
 @mquery['movies'][0]['mpaa_rating'].should == "#{mpaa_rating}"
The main difference, is that I’m passing the argument through to use as a validation check.  

Example 3: /features/movielookup_json_validation.feature

These tests I separated out of the other two.  These tests are made to just test the JSON functionality itself.

Given /^A request for an unknown movie is sent to the API$/ do

  @bquery = JSON.parse(open("http://api.rottentomatoes.com/api/public/v1.0/movies.json?apikey=jc7eaxjfpemb2uz7qsrudnsq&q=bbxa&page_limit=1").read)


Then /^the response should be zero movies returned$/ do

  @bquery['total'].should == 0


Given /^A API call is made for more then one movie$/ do

  @mquery = JSON.parse(open("http://api.rottentomatoes.com/api/public/v1.0/movies.json?apikey=jc7eaxjfpemb2uz7qsrudnsq&q=Toy+Story&page_limit=1").read)


Then /^the results wil have a total greater than 1$/ do

  @mquery['total'].should > 1


Basically in these two simple tests I'm checking that if a query is sent for a movie not in the RT movie database, that we get back a proper response. 

The second test verifies that if a query is sent for a movie with more then one hit (like Toy Story) it will display a total value greater the 1.

Leave a Reply

Your email address will not be published. Required fields are marked *