I was knocked out! I was asked a question about API testing and I was mentally knocked out. While I have tested APIs before, I have been focused on front-end testing lately. The last time I did it in an automated fashion was as a proof of concept. At that moment, I realized I have been focusing on front-end test automation too much and I really needed to brush up on my back-end testing skills.
Last weekend, I challenged myself to learn API testing two ways in two languages. I decided to do this in Ruby and Python. I am most comfortable with Ruby, so I wanted to be sure I knew an approach. As for Python, I have never worked with it before this challenge. As it is a popular language for programming in general and a common one for test automation, I decided it was a must try. I found it to be a straightforward language to learn and am looking forward to doing more work with it.
Why API Testing?
API Testing is the best way to test back-end endpoints and integrations. Having a solid API Testing framework in place can reduce some front-end testing needs and creates a solid cross platform testing strategy with mobile applications. In the challenge that I took, I focused on getting information for the API.
The Approach
I decided to go with functional test driven and behavioral driven test patterns for this challenge. In order to do this, I needed to find an API to test against. After a quick Google search, I found a list of APIs that are free for testing on GitHub (found here) and decided that I would work with the iTunes API for queries.
Functional Testing: Ruby
Starting with Ruby was the natural choice, as it was already installed on my computer and I wanted to get my feet wet. I went with Capybara as my driver in this exercise. Capybara is an awesome headless browser that enables fast testing. I have truly been enjoying it lately. Below is my code.
require 'json'
require 'rspec'
require 'ci/reporter/rake/test_unit_loader'
gem 'test-unit'
require 'test/unit/ui/console/testrunner'
require 'capybara'
require 'capybara/dsl'
require 'capybara/rspec'
require 'capybara/poltergeist'
require 'rest-client'
class API < Test::Unit::TestCase
include Capybara::DSL
def setup
Capybara.register_driver(:poltergeist) { |app| Capybara::Poltergeist::Driver.new(app, js_errors: false, timeout: 300, :phantomjs_options => ['--ssl-protocol=tlsv2']) } # , timeout: 300
Capybara.default_driver = :poltergeist # configure Capybara to use poltergeist as the driver
$driver = Capybara.current_session
end
def teardown
end
def test_itunes
response = RestClient.get 'https://itunes.apple.com/search?term=the+killers&entity=musicVideo'
assert_equal response.code,200
data_hash = JSON.parse(response)
result_count = data_hash['resultCount']
assert_equal result_count, 50
end
end
This is a straightforward approach that is to the point and that is why I like it. In this test, I’m only asserting two validation points, : the first is a status code of 200 and the second is that the default result Count is 50. This is not a sophisticated test, but instead a practical starting point.
Behavioral Driven Testing: Ruby
Sticking with Ruby, I switched gears to Behavioral Driven testing with Cucumber. I believe that Behavioral Driven testing is an excellent area of testing because, here you are focused on the user. With regards to API, it might as great a fit as Functional Driven testing, but it’s is one that speaks to Product. In this example I stuck with Capybara and will show you a few of the scenarios and steps that I used.
itunes.feature
Feature: Testing iTunes API Background: Given that I can access the iTunes API Scenario: Search for results of The Killers Then I can search for The Killers And get the Results Count Scenario: Search for Music Videos starting The Killers Then I can search for Hot Fuss by The Killers And see Hot Fuss in the results stream Scenario: Search for the catalog of a band Then I should be able to search for "La Roux" And see artist results for "La Roux"
itunes_steps.rb
Given (/^that I can access the iTunes API$/) do
$client = RestClient.get 'https://itunes.apple.com/search'
expect($client.code).to eq(200)
end
Then (/^I can search for The Killers$/) do
$client = RestClient.get 'https://itunes.apple.com/search?term=the+killers'
expect($client.code).to eq(200)
end
And (/^get the Results Count$/) do
data_hash = JSON.parse($client)
result_count = data_hash['resultCount']
expect(result_count).to eq(50)
end
Then (/^I can search for Hot Fuss by The Killers$/) do
$client = RestClient.get 'https://itunes.apple.com/search?term=the+killers+hot+fuss'
expect($client.code).to eq(200)
end
And (/^see Hot Fuss in the results stream$/) do
data_hash = JSON.parse($client)
result_count = data_hash['resultCount']
results_details = data_hash['results']
expect(result_count).to eq(11)
expect(results_details.to_s).to include("Hot Fuss")
end
Then (/^I should be able to search for "([^"]*)"$/) do |band|
band_name = band.gsub(/\s+/, '+')
$client = RestClient.get 'https://itunes.apple.com/search?term=' + band_name
expect($client.code).to eq(200)
end
And (/^see artist results for "([^"]*)"$/) do |band|
data_hash = JSON.parse($client)
results_details = data_hash['results']
expect(results_details.to_s).to include(band)
end
In this case, I did it a few different ways, hard coded (bad) and variable coded (good). This is again, more a less a proof of concept and not expected to be perfect. I was looking to experiment with the code, starting first on making it work and second on refining the code.
Functional Testing: Python
Finally, I decided to try my hand at Python. As I mentioned above, I had never worked in Python before this attempt. I found the language to be easy to pick up, it does have a look and feel similar to Ruby, so that made it easier for me.
import json
import requests
import unittest
class TestAPIReponses(unittest.TestCase):
def test_validate_status_code(self):
response = requests.get("https://itunes.apple.com/search?term=the+killers")
self.assertEqual(200, response.status_code)
def test_validate_results_count(self):
response = requests.get("https://itunes.apple.com/search?term=the+killers")
json_data = json.loads(response.content)
results = json_data['resultCount']
results_details = json_data['results']
self.assertEqual(50, results)
self.assertIn("Hot Fuss", str(results_details))
def test_japanese_music(self):
response = requests.get('https://itunes.apple.com/search?term=ayumi+hamasaki&limit=100')
json_data = json.loads(response.content)
results = json_data['resultCount']
results_details = json_data['results']
self.assertEqual(100, results)
self.assertIn("Ayumi Hamasaki", str(results_details))
if __name__ == '__main__':
unittest.main()
In this attempt I had three tests with several different assertions. This gave me an introduction into how asserts work in Python and how data is returned.
Conclusion
In this challenge, I wanted to prove to myself at least, that I had not lost my mind and my skills. When I first sat down to work on this challenge, I remember I had created a Module for returning information to the TestRail API in Ruby before. This is not perfect code befitting of a code review, but I wanted to show you my cards and thoughts when working through a challenge or proof of concept. Usually, I start by writing enough code as needed to test a proof of concept. This is usually a base page and a few tests around basic navigation and then I start to build out other classes after the initial tests are working and producing results. I refine the code later.
It is important to include API Testing in any testing strategy and should not be neglected. I’m glad I went forward with this challenged for that reason. I’ll continue to play with API testing in addition to my usual front-end testing efforts.
This challenge took less than a few (highly) interrupted hours. The two biggest problems were identifying an API to test against and then installing and ramping up on Python. I liked what I saw in Python and am looking forward to playing around with it further.
Connect with me
If you liked this post, take a quick minute to sign up.

