I Was Knocked Out This Is What I Did Next

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.

Leave a Reply