Как протестировать вызов API HTTParty с помощью Ruby и RSpec - PullRequest
0 голосов
/ 06 декабря 2018

Я использую гем HTTParty для вызова API GitHub для доступа к списку репозиториев пользователя.

Это очень простое приложение, использующее Sinatra, которое отображает любимый язык программирования пользователя на основе большинстваобщий язык, который появляется в их репозиториях.

Я немного застрял в том, как я могу написать ожидание RSpec, которое копирует фактический вызов API и вместо этого просто проверяет, возвращаются ли данные json.

У меня есть ложный файл .json, но я не уверен, как использовать его в моем тесте.

Есть идеи?

github_api.rb

require 'httparty'

class GithubApi
  attr_reader :username, :data, :languages

  def initialize(username)
    @username = username
    @response = HTTParty.get("https://api.github.com/users/#{@username}/repos")
    @data = JSON.parse(@response.body)
  end
end

github_api_spec.rb

require './app/models/github_api'
require 'spec_helper'

describe GithubApi do
  let(:github_api) { GithubApi.new('mock_user') }

  it "receives a json response" do

  end
end

Остальные файлы для наглядности:

results.rb

require 'httparty'
require_relative 'github_api'

class Results

 def initialize(github_api = Github.new(username))
   @github_api = github_api
   @languages = []
 end

 def get_languages
   @github_api.data.each do |repo|
     @languages << repo["language"]
   end
 end

 def favourite_language
   get_languages
   @languages.group_by(&:itself).values.max_by(&:size).first
 end
end

application_controller.rb

require './config/environment'
require 'sinatra/base'
require './app/models/github_api'

class ApplicationController < Sinatra::Base

  configure do
    enable :sessions
    set :session_secret, "@3x!ilt£"
    set :views, 'app/views'
  end

  get "/" do
    erb :index
  end

  post "/user" do
    @github = GithubApi.new(params[:username])
    @results = Results.new(@github)
    @language = @results.favourite_language
    session[:language] = @language
    session[:username] = params[:username]
    redirect '/results'
  end

  get "/results" do
    @language = session[:language]
    @username = session[:username]
    erb :results
  end

run! if app_file == $0

end

Ответы [ 2 ]

0 голосов
/ 07 декабря 2018

Существует несколько способов решения этой проблемы.

Вы можете, как предложил @anil, использовать такую ​​библиотеку, как webmock, чтобы высмеивать основной HTTP-вызов.Вы также делаете нечто подобное с видеомагнитофоном (https://github.com/vcr/vcr), который записывает результаты фактического вызова конечной точки HTTP и воспроизводит этот ответ при последующих запросах.

Но, учитывая ваш вопрос, я неЯ не понимаю, почему вы не можете просто использовать Rspec double. Я покажу вам, как это показано ниже. Но, во-первых, было бы немного проще протестировать код, если бы он не был все в конструкторе.

github_api.rb

require 'httparty'

class GithubApi
  attr_reader :username

  def initialize(username)
    @username = username
  end

  def favorite_language
    # method to calculate which language is used most by username
  end

  def languages
    # method to grab languages from repos
  end

  def repos
    repos ||= do
      response = HTTParty.get("https://api.github.com/users/#{username}/repos")
      JSON.parse(repos.body)
    end
  end
end

Обратите внимание, что вам не нужно ссылаться на переменную @username в URL, потому что у вас есть attr_reader.

github_api_spec.rb

require './app/models/github_api'
require 'spec_helper'

describe GithubApi do
  subject(:api) { described_class.new(username) }

  let(:username) { 'username' }

  describe '#repos' do
    let(:github_url) { "https://api.github.com/users/#{username}/repos" }
    let(:github_response) { instance_double(HTTParty::Response, body: github_response_body) }
    let(:github_response_body) { 'response_body' }

    before do
      allow(HTTParty).to receive(:get).and_return(github_response)
      allow(JSON).to receive(:parse)

      api.repos
    end

    it 'fetches the repos from Github api' do
      expect(HTTParty).to have_received(:get).with(github_url)
    end

    it 'parses the Github response' do
      expect(JSON).to have_received(:parse).with(github_response_body)
    end
  end
end

Обратите внимание, что на самом деле нет необходимости загружать или анализировать какой-либо настоящий JSON. Мы тестируем здесь то, что мы сделали правильный HTTP-вызов и что мы вызвали JSON.parse в ответе. Как только вы начнете тестировать метод languages, вам нужно будет на самом деле загрузить и проанализировать ваш тестовый файл, например так:

let(:parsed_response) { JSON.parse(File.read('path/to/test/file.json)) }
0 голосов
/ 06 декабря 2018

Вы можете смоделировать эти вызовы API с помощью https://github.com/bblimke/webmock и отправить обратно mock.json с помощью webmock.В этом посте https://robots.thoughtbot.com/how-to-stub-external-services-in-tests рассказывается о настройке webmock с RSpec (тесты в пост-фиктивном вызове API GitHub тоже)

...