如何使用Ruby和RSpec测试HTTParty API调用

时间:2018-12-06 15:10:31

标签: ruby rspec httparty

我正在使用HTTParty gem来调用GitHub API,以访问用户的存储库列表。

这是一个使用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 :(得分:2)

您可以使用https://github.com/bblimke/webmock模拟这些API调用,并使用webmock发送回ock.mock.json。这篇文章https://robots.thoughtbot.com/how-to-stub-external-services-in-tests引导您使用RSpec设置webmock(文章模拟GitHub API调用中的测试也是如此)

答案 1 :(得分:2)

有多种方法可以解决此问题。

您可以按照@anil的建议,使用像webmock这样的库来模拟基础的HTTP调用。您还可以使用VCR(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,因此无需在网址中引用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)) }