RSpec и Open-URI, как имитировать создание SocketError / TimeoutError

Я хочу указать, что когда Open-Uri open () вызывает тайм-аут или вызывает исключение, такое как SocketError, я обрабатываю вещи так, как ожидалось, однако у меня с этим возникают проблемы.

Вот моя спецификация (для SocketError):

@obj.should_receive(:open).with("some_url").and_raise(SocketError)

И часть моего объекта, где я использую open-uri:

begin
  resp = open(url)
  resp = resp.read
rescue SocketError
  something = true
end

Однако в этой ситуации спецификация не работает как с nil.read ошибкой.

Это второй раз на этой неделе, когда я столкнулся с этой проблемой, в прошлый раз я пытался смоделировать TimeoutError при переносе open() с помощью a timeout() {}, в этот раз я сдался и просто вызвал фактический тайм-аут, открыв класс. Очевидно, я мог бы вызвать SocketError, пытаясь вызвать недопустимый URL-адрес, но я уверен, что есть правильный способ высмеять это с помощью RSpec.

Обновление: я, очевидно, не понимал, что поздно ночью, ошибка была на самом деле, когда я повторно попробовал URL-адрес после SocketError, часть and_raise (SocketError) работала нормально.

Ответов (1)

Решение

Предоставленная вами строка должна работать на основе предоставленной вами информации: я сделал крошечный тестовый класс и спецификацию (см. Ниже) только с описанными функциями, и все вело себя так, как ожидалось. Было бы полезно, если бы вы могли предоставить немного больше контекста - например, полный блок «it» из спецификации может выявить некоторые другие проблемы.

Как уже упоминалось, проходит следующая спецификация, и я считаю, что она отражает логику, которую вы пытались проверить:

require 'rubygems'
require 'spec'

class Foo
  attr_accessor :socket_error

  def get(url)
    @socket_error = false
    begin
      resp = open(url)
      resp = resp.read
    rescue SocketError
      @socket_error = true
    end
  end
end

describe Foo do
  before do
    @foo = Foo.new
  end

  it "should handle socket errors" do
    @foo.should_receive(:open).with("http://www.google.com").and_raise(SocketError)
    @foo.get("http://www.google.com")
    @foo.socket_error.should be_true
  end
end