September 12, 2019

Are you sure the buses are still listed? Interacting with APIs with Ruby + NET::HTTP + Gauge

This is Part 2 of 2 of a blog series. Care to go back to the beginning

There are many different Ruby libraries that allow you to interact with an API:

  • Net/Http: The HTTP client built into Ruby standard library. 
  • Httparty: Built on top of Net/Http by John Nunemaker, you can GET the HTTP Response HTTP Code, Response Message, and the HTTP Headers with one call. The Google Group was last active in 2017. 
  • Faraday: Also allows you to get the status, headers, and body, allowing you a bit more to customize the HTTP request
  • Rest-Client: a "simple HTTP and REST client for Ruby, inspired by the Sinatra’s microframework style of specifying actions: get, put, post, delete".
For this sample project, where we are simply getting data from the MBTA API, we will use:

  • Net/HTTP to get data from the API
  • The JSON library to parse the data
  • The test/unit library to assert that the expected values and the actual values match up
  • ThoughtWorks Gauge as the test framework. 

Before we make the test data-driven, using the ThoughtWorks Gauge test framework and the table of data in our last segment of this blog, let's focus on one single data point...

What Data Can We Retrieve For Bus Route 230? 


Let's say we wanted to access all the information the Massachusetts Bay Transportation Authority (MBTA) has for the Route 230 bus route:

According to the MBTA V2 API developers documentation, since there is no API Key we need to use, we could open up Google Chrome and go to the URL, https://api-v3.mbta.com/routes/230:

 {  
  "data": {  
   "attributes": {  
    "color": "FFC72C",  
    "description": "Local Bus",  
    "direction_destinations": [  
     "Montello Commuter Rail Station",  
     "Quincy Center"  
    ],  
    "direction_names": [  
     "Outbound",  
     "Inbound"  
    ],  
    "fare_class": "Local Bus",  
    "long_name": "Montello Commuter Rail Station - Quincy Center",  
    "short_name": "230",  
    "sort_order": 52300,  
    "text_color": "000000",  
    "type": 3  
   },  

How could we do this programmatically?

Create an HTTP Request with Net::HTTP::Get

According to ToolsQA.com, an "HTTP Request is a packet of Information that one computer sends to another computer to communicate something. To its core, HTTP Request is a packet of binary data sent by the Client to server".

As part of the HTTP Request, we can see if we can GET information stored in the Uniform Resource Locator, https://api-v3.mbta.com/routes/230.

  • View more information about HTTP Methods such as GET, POST, PUT, PATCH at the W3Schools

After requiring the Net/Http library, we convert the URL into a URI using the Ruby gem of the same name. The URI Ruby gem goes to the URL and breaks it into Uniform Resource Identifier components such as the hostname and the port name.

The URI information is then passed into a new HTTP Request.

 uri = URI("https://api-v3.mbta.com/routes/230  
 request = Net::HTTP::Get.new(uri)  

Set Up HTTP Request Options to SSL and HTTPS


The MBTA API uses SSL a, "Secure Sockets Layer and, in short, it's the standard technology for keeping an internet connection secure and safeguarding any sensitive data that is being sent between two systems, preventing criminals from reading and modifying any information transferred, including potential personal details", according to Symantec.

If we just connected with the Net/Http gem using HTTP instead of HTTPS, we would not be able to retrieve data. For the Net/Http gem, we need to turn SSL options on, detailing what scheme the URI should be:

 req_options = {  
   use_ssl: uri.scheme == "https"  
  }  

Feed Net/Http the HTTP Request, Get the HTTP Response Code


Now that we have crafted the HTTP Request, and added HTTPS as the scheme as part of the required options, we can feed both into Net/Http, saving the HTTP Response in a variable we can call response:

  response = Net::HTTP.start(uri.hostname, uri.port, req_options) do |http|  
   http.request(request)  
  end  


HTTP response status codes indicate whether a specific HTTP request has been successfully completed

Was everything successful? We could find out by printing out the HTTP Response Status codes to the screen:

puts response.code
  • 200 if successful
  • 401 if unauthorized
  • 404 if not found
  • 500 if internal service error
With our test, we only want it to pass if the response.code is actually "200". Let's use the Ruby gem 'test/unit' to check to see if the expected "200" and actual values (response.code) are equal:

assert_equal("200", response.code)  


Examine the Response Body To Check the Long Name of the 230 Bus Route


If we were to print the entire JSON response.body, all text shown in https://api-v3.mbta.com/routes/230 would be displayed.

If we only wanted to collect all the data attribute for route 230, we could use the JSON library to parse those out into a variable called attributes:

 attributes = JSON.parse(response.body)['data']['attributes']  

If we then wanted to search these stored attributes hashed together to find the long_name, we could search for the value that matched the key, long_name, by using the code: attributes['long_name'].

 assert_equal("Montello Commuter Rail Station - Quincy Center", attributes['long_name'])  

Add in ThoughtWorks Gauge

Previously, we created a data table using ThoughtWorks Gauge in a specification file:

routes_long_name.spec:
 # ROUTE: Verify that the Long Name is Returned  
   
 Given the ID, verify that the route api returns the  
 long_name of the route.  
   
 |route| long_name                         |  
 |-----------------------------------------|  
 | 210 | Quincy Center - Fields Corner     |  
 | 212 | Quincy Center - North Quincy      |  
 | 220 | Hingham Depot - Quincy Center     |  
 | 222 | East Weymouth - Quincy Center     |  
 | 230 | Montello Commuter Rail Station - Quincy Center |  
 | 236 | South Shore Plaza - Quincy Center |  
   
 ## Given the route id return the long_name  
 * Passing <route> to ROUTES api returns <long_name>  

For each entry listed above, the route and long name would be passed into the step, Passing <route> to ROUTES api returns <long_name>.

Following the code we listed above, our step_implementation would look like:

find_longname_spec.rb
 require 'net/http'  
 require 'test/unit'  
 require 'json'  
 include Test::Unit::Assertions  
   
 step 'Passing <route> to ROUTES api returns <long_name>', continue_on_failure: true do |route, long_name|  
  uri = URI("https://api-v3.mbta.com/routes/#{route}")  
  puts "Connecting to: #{uri}"  
   
  request = Net::HTTP::Get.new(uri)  
   
  req_options = {  
   use_ssl: uri.scheme == "https"  
  }  
   
  response = Net::HTTP.start(uri.hostname, uri.port, req_options) do |http|  
   http.request(request)  
  end  
   
  assert_equal("200", response.code)  
   
  attributes = JSON.parse(response.body)['data']['attributes']  
  assert_equal(long_name, attributes['long_name'])  
 end  


... And that's how you can create data-driven API Testing using Ruby's Net/HTTP Gem! Want to try it out yourself? Download the code off my GitHub site, gauge-ruby-api.


Are you sure the buses are still listed? 
Data-driven API tests with Ruby + NET::HTTP + ThoughtWorks Gauge:


Happy Testing!

-T.J. Maher
Sr. QA Engineer, Software Engineer in Test
Meetup Organizer, Ministry of Testing - Boston

Twitter | YouTubeLinkedIn | Articles

17 comments:

James Horner said...

Would love to explore more interesting posts like this one.
ERP Development Melbourne
seo agency Melbourne
Custom software development Melbourne

arshiya fouzia said...

It is very nice information about the digital marketing.Thanks for sharing with us.
Software testing course

sites.google said...

This post is extremely superb. I extremely like this post. It is outstanding among other posts that I see read in quite a while. You rock for this better than average post. I truly value it!

스포츠토토
바카라사이트
파워볼 메이저사이트
카지노사이트

feedsfloor said...

Exceptionally marvelous !!! When I look for this I discovered this site at the highest point of all websites in web crawler. Personally I think overjoyed I discovered the blogs.

토토
스포츠토토
토토사이트
먹튀검증

chaparralboats said...

I found so many interesting stuff in your blog especially its discussion. From the tons of comments on your articles, I guess I am not the only one having all the enjoyment here! keep up the good work.

사설토토
온라인카지노
파워볼
온라인바카라

keo nhacai said...

That's a great article! The neatly organized content is good to see. Can I quote a blog and write it on my blog? My blog has a variety of communities including these articles. Would you like to visit me later? keo nhacai


admin said...

google 193
google 194
google 195
google 196
google 197
google 198
google 199

japanyadongcom said...

Excellent site you’ve got here.. It’s hard to find high-quality writing like yours nowadays. I seriously appreciate individuals like you! Take care!! Feel free to visit my website; 한국야동

koreayadongcom said...

Thank you so much for this information, I’m always in touch with you. Update more information about this related blog. Feel free to visit my website;
국산야동

yahanvideonet said...


You made some good points there. I did a Google search about the topic and found most people will believe your blog. Feel free to visit my website; 일본야동

casinosite777.info said...

Really very beneficial tips are provided here and, Thank you so much. Keep up the good works.
바카라사이트

Eliaz Beth said...

I wanted to thank you for this excellent read!! I definitely loved every little bit of it. I have you bookmarked your site to check out the new stuff you post. riatoto

joseph kuruvilla said...

Important and interesting update thanks for sharing the information dear author!
Inventory Management Software

norsk førerkort said...

Kjøp ekte og registrert førerkort fra nettsiden vår uten å skrive eksamen eller ta praksisprøven. alt vi trenger er opplysningene dine, og de vil bli registrert i systemet innen de neste åtte dagene. kjøp førerkort belgia, kjøp førerkort belgia, kjøp førerkort i nederland, førerkort b belgia, kjøp førerkort med registrering.
kjøpe førerkort.

ostaa ajokortti.

kopa korkort.

kjøp førerkort.

kop svenskt korkort.

kupete shof’orska knizhka.

købe kørekort.

sig sauer p320 m17 .

kjop forerkort.

cumpara permis de conducere .
Kaufen Sie den Führerschein in Frankreich ohne Prüfung. Wir bieten absolut alle Führerscheinklassen in Deutschland, Österreich und der Schweiz an.

Robin said...

I really enjoy studying on this site, it holds fantastic blog posts website design. You should keep it up forever! Best of luck. Infracciones Trafico VA Chesterfield

tamo rene said...

https://kokozukaufen.de/product/afghanisches-heroin-kaufen/
https://originaltforerkort.eu/product/kjop-forerkort-online/

Anil said...

APTRON caters to learners of all levels. With state-of-the-art facilities and a commitment to excellence, we strive to empower our students to harness the power of data and drive meaningful insights. Join APTRON's Data Science Training in Gurgaon and embark on a journey towards a rewarding and impactful career in the realm of data science.