lundi 9 octobre 2017

Testing external API calls (made with flickraw) in Rails 5 using Minitest

I'm creating a Ruby on Rails app that takes a random location (from a database of locations) and uses that information to make some calls to the Flickr API (via the Flickraw gem) to get photos of that location. I've figured that part out, but I'm struggling to figure out how to test it. I'm using this project as a way to teach myself a number of things, including how to write unit and integration tests (with Minitest), but I'm really struggling with the correct way to run an integration test on an external API call via the Flickraw gem.

I created a service called get_photos.rb that the controller calls when the index loads that goes out to Flickr to find the Flickr place_id of the city or country, then once it has that information, it looks for pictures of that location. It gets the photo URL and the username and profile link of the user who uploaded it and displays all of those on the page.

I know that I can't make an API request every single time I run a test, but I'm struggling to get set up with Webmock or VCR because the documentation I've found for them doesn't seem to cover the case where I use a gem to help with my API calls. However, I think it's more likely that I just plain don't understand anything that I'm looking at with these tests. I read through the documentation for Webmock and VCR and I searched SO, google, and reddit for help, but I've been struggling with this for three days and I haven't found anything to explain this to me properly.

Here is get_photos.rb (I'm sure I am doing many things inefficiently right now; I'm still learning! I want to get tests set up correctly before I make any more changes to this)

require 'flickraw'

# Service to access the Flickr API to get photos to display on places/index
class GetPhotos

  # load API keys
  FlickRaw.api_key=ENV['FLICKR_KEY']
  FlickRaw.shared_secret=ENV['FLICKR_SECRET']

  def initialize(place)

    # get the Flickr ID for the city
    find_place = flickr.places.find :query => place.city

    # if the city doesn't exist, then check the country
    if find_place != []
      @place = find_place[0]["place_id"]
    else
      find_place = flickr.places.find :query => place.country
      @place = find_place[0]["place_id"]
    end

    # look for photos of that place and put them in a list
    list = flickr.photos.search :place_id => @place, :tags => "travel", :safe_search => '1' 

    # make sure the list actually contains something
    @list_len = list.length
    if @list_len == 0
      # put a placeholder image in there for now
      @photo = "http://ift.tt/2xto96L" 
    elsif @list_len == 1
        @photo = list[0]     
    else
      index = Random.new.rand(0..@list_len)
      @photo = list[index]
      @id = @photo.id
      @secret = @photo.secret
      @info = flickr.photos.getInfo :photo_id => @id, :secret => @secret
    end

  end

  def photos_list
    uploaded_by(@photo)
    profile_link(@photo)
  end

  def uploaded_by
    if @list_len == 0
      return "Sorry, looks like Flickr doesn't have a photo for this location!"
    else
      return "Photo by #{@info["owner"]["username"]} on Flickr"
    end
  end

  def profile_link
    if @list_len == 0
      return "#"
    else
      url = FlickRaw.url_profile(@info)
      return url
    end
  end

  def photo_url
    if @list_len == 0
      return @photo
    else
      FlickRaw.url_b(@info)
    end
  end

end

And here are the test cases I've built so far (no VCR; just an attempt at Webmock)

class IndexTest < ActionDispatch::IntegrationTest
  def setup
    @photoless_place = places(:mekambo)
    stub_request(:post, "http://ift.tt/MVfi6Q").
          to_return(status: 200, body: "", headers: {})
  end
  test "flickraw gets the right location code" do
    get places_path
  end

  test "photos and information pulled from Flickr API when there are 3 pictures" do
    get places_path
    assert_template 'places/index'
    assert_not_empty 'div.pic1'
    assert_not_empty 'div.pic2'
    assert_not_empty 'div.pic3'
  end
end

I'd appreciate any help I can get with this!

Aucun commentaire:

Enregistrer un commentaire