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

dwa*_*h91 9 ruby rspec httparty

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

这是一个使用 Sinatra 的非常简单的应用程序,它根据用户存储库中出现的最常用语言显示用户最喜欢的编程语言。

我对如何编写一个模拟实际 API 调用的 RSpec 期望值有点困惑,而只是检查是否正在返回 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
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

为清楚起见,其余文件:

结果.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
Run Code Online (Sandbox Code Playgroud)

应用控制器.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
Run Code Online (Sandbox Code Playgroud)

ari*_*ver 11

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

正如@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(response.body)
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

请注意,您不需要@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
Run Code Online (Sandbox Code Playgroud)

请注意,不需要实际加载或解析任何真正的 JSON。我们在这里测试的是我们进行了正确的 HTTP 调用并且我们调用JSON.parse了响应。一旦开始测试该languages方法,您就需要实际加载和解析您的测试文件,如下所示:

let(:parsed_response) { JSON.parse(File.read('path/to/test/file.json')) }
Run Code Online (Sandbox Code Playgroud)