How should I test this code with rspec rails? - ruby-on-rails

In my rails application I have a module with an API call that I would like to write rspec tests for. What would you write as proper tests for this? I have read not to combine httparty with rspec because it is very slow and now I have no idea how to do this. Thanks for the advice!
module BandsInTown
class API
attr_reader :artist_name, :info, :events
def initialize(artist_name)
#artist_name = artist_name
end
def artist_info
#info = fetch_data
end
def artist_events
#events = fetch_data 'events'
end
private
def fetch_data(endpoint = nil)
request_url = "http://api.bandsintown.com/artists/#{[#artist_name, endpoint].compact.join('/')}.json?api_version=2.0&app_id=AUTH_KEY"
resp = HTTParty.get(request_url)
return false if resp.code != 200
resp
end
end
end

I would use webmock to get around making API requests.
Here's an example on how the code in yout spec_helper.rb could look like:
require 'webmock/rspec'
def stub_api_requests
response = File.read('spec/fixtures/payload.json')
stub_request(:get, %r{http:\/\/api.bandsintown.com\/artists/\/(.)*})
.to_return(
status: 200,
body: response
)
end
config.before(:each) do
stub_api_requests
end

Related

How to refactor ruby rest-client get method

I'm using Rubys rest-client gem to make a call to Google API and want to shorten the url part.
Current code:
class GoogleTimezoneGetter
def initialize(lat:, lon:)
#lat = lat
#lon = lon
#time_stamp = Time.new.to_i
end
def response
response = RestClient.get "https://maps.googleapis.com/maps/api/timezone/json?location=#{#lat},#{#lon}&timestamp=#{#time_stamp}&key=#{GOOGLE_TIME_ZONE_KEY}"
JSON.parse(response)
end
def time_zone
response["timeZoneId"]
end
end
I would like to be able to do something like:
def response
response = RestClient.get (uri, params)
JSON.parse(response)
end
But I'm struggling to find out how to do so.
To make the class a bit tidier, I'd like to break the url down into 'uri' and 'params'. I think the rest-client gem allows you to do this but I can't find specific examples.
I want to put the
{#lat},#{#lon}&timestamp=#{#time_stamp}&key=#{GOOGLE_TIME_ZONE_KEY}"
in to a 'params' method and pass that to the RestClient.get method.
Have you check the rest-client gem readme?
They did give a specific example on this (below example quoted from the readme)
RestClient.get 'http://example.com/resource', {params: {id: 50, 'foo' => 'bar'}}
In your case, it should be something like this
def url
"https://maps.googleapis.com/maps/api/timezone/json"
end
def params
{
locations: "#{#lat},#{#lon}",
timestamp: #time_stamp,
key: GOOGLE_TIME_ZONE_KEY
}
end
def response
response = RestClient.get(url, params: params)
JSON.parse(response)
end
rest-client already accepts a hash for params. If you prefer a bunch of little methods on your class, you can divide out each step to a method and keep everything readable.
class GoogleTimezoneGetter
def initialize(lat:, lon:)
#lat = lat
#lon = lon
#time_stamp = Time.new.to_i
end
def response
response = RestClient.get gtz_url, params: { gtz_params }
JSON.parse(response)
end
def time_zone
response["timeZoneId"]
end
def gtz_url
"https://maps.googleapis.com/maps/api/timezone/json"
end
def gtz_params
return {location: "#{#lat},#{#lon}", timestamp: #time_stamp, key: GOOGLE_TIME_ZONE_KEY }
end
end

If open-uri works, why does net/http return an empty string?

I am attempting to download a page from Wikipedia. For such a task, I am using gems. When using net/http, all I get is an empty string. So I tried with open-uri and it works fine.
Nevertheless, I prefer the first option because it gives me a much more explicit control; but why is it returning an empty string?
class Downloader
attr_accessor :entry, :url, :page
def initialize
# require 'net/http'
require 'open-uri'
end
def getEntry
print "Article name? "
#entry = gets.chomp
end
def getURL(entry)
if entry.include?(" ")
#url = "http://en.wikipedia.org/wiki/" + entry.gsub!(/\s/, "_")
else
#url = "http://en.wikipedia.org/wiki/" + entry
end
#url.downcase!
end
def getPage(url)
=begin THIS FAULTY SOLUTION RETURNS AN EMPTY STRING ???
connector = URI.parse(url)
connection = Net::HTTP.start(connector.host, connector.port) do |http|
http.get(connector.path)
end
puts "Body:"
#page = connection.body
=end
#page = open(url).read
end
end
test = Downloader.new
test.getEntry
test.getURL(test.entry)
test.getPage(test.url)
puts test.page
P.S.: I am an autodidact programmer so the code might not fit good practices. My apologies.
Because your request return 301 Redirect (check connection.code value), you should follow redirect manually if you are using net/http. Here is more details.

Checking user email calling Closio API in Rails - HTTParty and no method errors

I'm working with a team on checking a user's email input when they sign up for a web app. The user will not be allowed to sign up if their email is not found with the following API call using HTTParty. We are getting method_errors for whatever syntax is first within the function. For, example, in the method below, "include" comes up as an undefined method error.
def email_checker
include HTTParty
default_params :output => 'json'
format :json
base_uri 'app.close.io'
basic_auth 'insert_api_code_here', ' '
response = HTTParty.get('/api/v1/contact/')
#email_database = []
response['data'].each do |x|
x['emails'].each do |contact_info|
#email_database << contact_info['email']
end
end
unless #email_database.include? :email
errors.add :email, 'According to our records, your email has not been found!'
end
end
UPDATE: So we went with the inline version of using HTTParty and our registrations controller (working with devise) looks like this:
class RegistrationsController < Devise::RegistrationsController
def email_checker(email)
YAML.load(File.read('config/environments/local_env.yml')).each {|k, v| ENV[k.to_s] = v}
api_options = {
query: => {:output => 'json'},
format: :json,
base_uri: 'app.close.io',
basic_auth: ENV["API_KEY"], ' '
}
response = HTTParty.get('/api/v1/contact/', api_options)
#email_database = []
response['data'].each do |x|
x['emails'].each do |contact_info|
#email_database << contact_info['email']
end
end
unless #email_database.include? email
return false
else
return true
end
end
def create
super
if email_checker == false
direct_to 'users/sign_up'
#and return to signup with errors
else
User.save!
end
end
end
We're getting syntax error: "syntax error, unexpected =>" Did we screw up the format?
There are two different ways to use HTTParty, and you're trying to use both. Pick one :).
The class-based method would look something like this:
class CloseIo
include HTTParty
default_params :output => 'json'
format :json
base_uri 'app.close.io'
basic_auth 'insert_api_code_here', ' '
end
class UserController
def email_checker
response = CloseIo.get('/api/v1/contact/')
# ... the rest of your stuff
end
end
An inline version would look something like this
class UserController
def email_checker
api_options = {
query: :output => 'json',
format: :json,
base_uri: 'app.close.io',
basic_auth: 'insert_api_code_here'
}
response = HTTParty.get('/api/v1/contact/', api_options)
# ... do stuff
end
end

How to test such class behavior in Rspec

I have a class which is responsible for dealing with some response from payments gateway.
Let's say:
class PaymentReceiver
def initialize(gateway_response)
#gateway_response = gateway_response
end
def handle_response
if #gateway_response['NC_STATUS'] != '0'
if order
order.fail_payment
else
raise 'LackOfProperOrder'
# Log lack of proper order
end
end
end
private
def order
#order ||= Order.where(id: #gateway_response['orderID']).unpaid.first
end
end
In payload from payment I've NC_STATUS
which is responsible for information if payment succeed and orderID which refers to Order ActiveRecord class byid`.
I would like to test behavior(in rspec):
If PaymentReceiver receives response where NC_STATUS != 0 sends fail_payment to specific Order object referred by orderID.
How you would approach to testing this ? I assume that also design could be bad ...
You have to make refactorization to remove SRP and DIR principles violations.
Something below I'd say:
class PaymentReceiver
def initialize(response)
#response = response
end
def handle_response
if #response.success?
#response.order.pay
else
#response.order.fail_payment
end
end
end
# it wraps output paramteres only !
class PaymentResponse
def initialize(response)
#response = response
end
def order
# maybe we can check if order exists
#order ||= Order.find(#response['orderID'].to_i)
end
def success?
#response['NCSTATUS'] == '0'
end
end
p = PaymentReceiver.new(PaymentResponse({'NCSTATUS' => '0' }))
p.handle_response
Then testing everything is easy.

net/http hanging requests causing failure - RoR

I have a bit of code that checks the response code of a list of URL's and presents them back - I am having trouble with a few of URL's that are hanging which causes the application not load at all. How can I make the request to give up after 30 seconds and check the next URL marking the skipped URL as failure.
below is my current code;
(Model/status.rb)
require "net/http"
require "uri"
class Status
def initialize(url)
#url = url
end
def get_status
response.code
end
def active?
["200","203","302"].include?(get_status) ? true : false
end
private
def lookup
URI.parse(#url)
end
def http
Net::HTTP.new(lookup.host, lookup.port)
end
def request
Net::HTTP::Get.new(lookup.request_uri)
end
def response
http.request(request)
end
end
(controllers/welcome_controller.rb)
class WelcomeController < ApplicationController
def index
#syndication = [
["http://v1.syndication.u01.example.uk/organisations?apikey=bbccdd", "U.INT 01"],
["http://v1.syndication.u02.example.uk/organisations?apikey=bbccdd", "U.INT 02"],
].collect { |url| logger.info("Boom #{url[0]}"); ["#{url[1]} (#{url[0]})", Status.new(url[0]).active?] }
end
end
Got the answer..
adding the following to my "def get_status"
def get_status
begin
response.code
rescue Exception => e
Rails.logger.info("Error #{e}")
end
end
This logged the error and the went to the next URL

Resources