模拟 GoogleAPI 请求

Mock GoogleAPI request

我正在使用 google-maps gem.

我正在尝试 mock/stub api 请求失败。

module GoogleMap
  class Route
    attr_accessor :start_location, :end_location

    def initialize(start_location, end_location)
      @start_location = start_location
      @end_location = end_location
    end

    def driving_duration_in_seconds
      route.duration.value
    end

    def driving_distance_in_meters
      route.distance.value
    end

    def driving_distance_hash
      return unless start_location && end_location

      { distance_in_meters: driving_distance_in_meters, duration_in_seconds: driving_duration_in_seconds }
    end

    private

    def coordinates_as_strings(location)
      "#{location.latitude},#{location.longitude}"
    end

    def route
      @route ||= Google::Maps.route(coordinates_as_strings(start_location), coordinates_as_strings(end_location))
    end
  end
end

我需要存根:

 WebMock::NetConnectNotAllowedError:
   Real HTTP connections are disabled. Unregistered request: GET https://maps.googleapis.com/maps/api/directions/json?destination=37.19687112,116.43791248&key=<apikey>&language=en&origin=2.15362819,-81.63712649 with headers {'Accept'=>'*/*', 'Date'=>'Sat, 12 Feb 2022 21:35:55 GMT', 'User-Agent'=>'HTTPClient/1.0 (2.8.3, ruby 2.7.2 (2020-10-01))'}
 
   You can stub this request with the following snippet:
 
   stub_request(:get, "https://maps.googleapis.com/maps/api/directions/json?destination=37.19687112,116.43791248&key=<apikey>&language=en&origin=2.15362819,-81.63712649").
     with(
       headers: {
      'Accept'=>'*/*',
      'Date'=>'Sat, 12 Feb 2022 21:35:55 GMT',
      'User-Agent'=>'HTTPClient/1.0 (2.8.3, ruby 2.7.2 (2020-10-01))'
       }).
     to_return(status: 200, body: "", headers: {})

如果我尝试最基本的存根,我会得到一个错误:

    stub_request(:any, /maps.googleapis.com/).
    to_return(status: 200, body: '', headers: {})
     Google::Maps::InvalidResponseException:
       unknown error: 783: unexpected token at ''
     # .../gems/ruby-2.7.2/gems/google-maps-3.0.7/lib/google_maps/api.rb:64:in `rescue in response'
     # .../gems/ruby-2.7.2/gems/google-maps-3.0.7/lib/google_maps/api.rb:60:in `response'
     # .../.rvm/gems/ruby-2.7.2/gems/google-maps-3.0.7/lib/google_maps/api.rb:27:in `query'

我认为这是错误的,因为我没有传递密钥。但我不明白为什么我必须将有效的 api 密钥传递到网络模拟中。

我也不会用任何东西来定义我的路线。为了测试 route 可以 return route.distance.value 等,我需要模拟一些东西。

对于其他测试,我在模拟实例方面是成功的,但是为了测试这个 lib 它确实有效,我觉得模拟实例方法而不是实际调用 api 是浪费测试。也许这只是浪费时间,我应该假设它有效,因为我使用的是 gem.

但我期待这样的事情:

RSpec.describe GoogleMap do
  let(:start_location) { create(:location) }
  let(:end_location) { create(:location) }

  context 'GoogleMaps::Route.new(start_location, end_location)' do
    let(:subject) { GoogleMap::Route.new(start_location, end_location) }

    # I have not been successful in stubbing this with the correct regex

    # stub_request(:get, "https://maps.googleapis.com/maps/api/directions/json?destination=<lat>,<long>key=<key>&language=en&origin=<lat>,<long>").
    # with(
    #   headers: {
    #  'Accept'=>'*/*',
    #  'Date'=>'Thu, 10 Feb 2022 21:09:02 GMT',
    #  'User-Agent'=>'HTTPClient/1.0 (2.8.3, ruby 2.7.2 (2020-10-01))'
    #   }).
    # to_return(status: 200, body: "", headers: {})
    # stub_request(:get, %r{https:\/\/maps\.googleapis\.com\/maps\/api\/directions\/json\?destination=.+,.+&key=.+&language=en&origin=.+,.+}).
    # stub_request(:any, /maps.googleapis.com/).
    # to_return(status: 200, body: '', headers: {})

    xit 'gives driving distance in seconds'
    xit 'gives driving duration in meters'
  end
end

您的 WebMock 工作正常。 Google::Maps::InvalidResponseException 在 WebMock 替换网络调用后引发。在引发异常时,Google Maps API 客户端正在尝试解析网络调用 returned 的内容,即 ''.

它期待一些 valid JSON to be returned。如果你有你的模拟 return {} 应该越过那条线。不过,它稍后可能会偶然发现其他一些异常,因为 gem 需要特定的模式。

如果你想继续沿着这条路走下去,你可以挖掘出来并添加一个有效的回复。但是,我建议不要模拟网络请求,因为这是第三方代码片段的实现细节,可能随时更改 - 使您的测试失败。相反,我会模拟出 Google::Maps.route 到 return 你需要的东西。