【问题标题】:Testing RestClient::Request.execute in RSpec在 RSpec 中测试 RestClient::Request.execute
【发布时间】:2016-05-20 23:28:25
【问题描述】:

我正在尝试测试“ApiClient.do_request”是否正在发送正确的参数并调用“RestClient::Request.execute”。但是,我的以下规格没有按预期工作。 RSpec 无法正确调用“RestClient::Request.execute”,因为该方法的“response”变量一直返回为 nil,这就是为什么我在调用 JSON.parse(response) 时得到以下 TypeError 的原因。对我来说奇怪的是,在 Rails 控制台中浏览该过程时我没有任何问题。我敢肯定我在这里遗漏了一些明显的东西......有什么想法为什么会发生这种情况,或者关于如何更有效地测试它的建议?

型号:

class ApiClient < ActiveRecord::Base

  BASE_PATH = "http://api.bandsintown.com/artists/"
  APP_ID = ENV["APP_ID"]

  def do_request(method:, base_url:BASE_PATH, app_id:APP_ID, url:, format:"json", options: nil)
    response = RestClient::Request.execute(method: method.to_sym, 
                                           url: "#{base_url}#{url}.#{format}?api_version=2.0&app_id=#{app_id}#{options}", 
                                           timeout: 10)

    JSON.parse(response)
  end

规格:

describe ApiClient do

  describe "do_request" do

    context "when all required arguments are present" do
      it "RestClient executes the request" do
        @test_client = ApiClient.new

        expect(RestClient::Request).to receive(:execute).with(:method=>:get, :url=> "http://api.bandsintown.com/artists/Damien%20Jurado/events/search.json?api_version=2.0&app_id=ShowBoatTest&location=San+Diego,CA&radius=15", :timeout=>10)

        @test_client.do_request(method:"get", app_id:"ShowBoatTest",url:"Damien%20Jurado/events/search",options:"&location=San+Diego,CA&radius=15")
      end
    end
  end

RSpec 错误:

  1) ApiClient do_request when all required arguments are present RestClient executes the request
 Failure/Error: JSON.parse(response)

 TypeError:
   no implicit conversion of nil into String
 # /Users/slamflipstrom/.rvm/gems/ruby-2.1.5/gems/json-1.8.3/lib/json/common.rb:155:in `initialize'
 # /Users/slamflipstrom/.rvm/gems/ruby-2.1.5/gems/json-1.8.3/lib/json/common.rb:155:in `new'
 # /Users/slamflipstrom/.rvm/gems/ruby-2.1.5/gems/json-1.8.3/lib/json/common.rb:155:in `parse'
 # ./app/models/api_client.rb:12:in `do_request'
 # ./spec/models/api_client_spec.rb:13:in `block (4 levels) in <top (required)>'

【问题讨论】:

  • RSpec 错误似乎来自另一个测试。即“当请求位置‘选项’时接收到‘选项’参数”。
  • 它们实际上是同一个测试,但我错误地包含了旧版本的错误消息。我已更新上述 RSpec 错误以反映更新后的测试名称。

标签: ruby-on-rails ruby rspec rest-client


【解决方案1】:

不考虑ApiClient 类中的api_version=2.0&amp;app_id=ShowBoat 之类的小语法错误,问题似乎是由您的RestClient::Request.execute 请求返回nil 引起的。

调试或检查response 的值并确保它不是nil

class ApiClient < ActiveRecord::Base

  BASE_PATH = "http://api.bandsintown.com/artists/"
  APP_ID = ENV["APP_ID"]

  def do_request(method:, base_url:BASE_PATH, app_id:APP_ID, url:, format:"json", options: nil)
    response = RestClient::Request.execute(method: method.to_sym, 
                                           url: "#{base_url}#{url}.#{format}?api_version=2.0&app_id=#{app_id}#{options}", 
                                           timeout: 10)
    puts response.inspect
    response ? JSON.parse(response) : []
  end

另一方面,您正在测试ApiClient 类的实现。换句话说,您正在测试该类是否以特定方式在内部调用某个其他类。例如,如果您决定稍后将 RestClient 替换为 HTTParty,您的测试将失败(即使它们不应该失败,因为您的类仍然可以正常工作)。

因此,测试类的实现会使您的测试变得“脆弱”。相反,请提供输入并测试预期的正确输出。

describe ApiClient do
  context "with all required arguments" do
    describe "#do_request" do
      it "returns object in correct format" do
        response = subject.do_request(method:"get", app_id:"ShowBoatTest",url:"Damien%20Jurado/events/search",options:"&location=San+Diego,CA&radius=15")
        expect(response.body).to include(title: "Damien Jurado @ The Casbah in San Diego, CA")
        # etc.
      end
    end
  end
end

【讨论】:

  • 我仍然对为什么“响应”变量继续返回为零感到困惑,但关于测试脆弱性的反馈是我所怀疑的。就目前而言,我觉得我应该只是将测试更改为更灵活。谢谢!
猜你喜欢
  • 2012-12-25
  • 1970-01-01
  • 2015-06-02
  • 2015-03-12
  • 1970-01-01
  • 1970-01-01
  • 2016-02-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多