Заглушка вызовов API в контроллере с помощью rspec

Я просто немного смущен тем, почему я не могу заглушить локальную переменную в моей спецификации контроллера.

Вот мой контроллер:

Class UsersController < ApplicationController
    ...
    def get_company
        resp = Net::HTTP.get("http://get_company_from_user_id.com/#{params[:id]}.json")
        @resp = JSON.parse(resp.body)
        ...

Моя спецификация выглядит так:

class ResponseHelper
    def initialize(body)
        @body = body
    end
end

describe "Get company" do
it "returns successful response" do
        stub_resp_body = '{"company": "example"}' 
        stub_resp = ResponseHelper.new(stub_resp_body)
    controller.stub!(:resp).and_return(stub_resp)
    get :get_company, {:id => @test_user.id}
    expect(response.status).to eq(200)
    end
end

Я все еще получаю сообщение об ошибке:

 Errno::ECONNREFUSED:
 Connection refused - connect(2)

Что я делаю неправильно? Если я заглушаю переменную resp, почему она все еще пытается выполнить HTTP-запрос, и как мне в этом случае заглушить переменную resp?


person Neeran    schedule 30.07.2013    source источник
comment
Не отвечаю на вопрос, но строковая интерполяция не работает со строками в одинарных кавычках.   -  person Idan Arye    schedule 30.07.2013
comment
Я предлагаю использовать WebMock github.com/bblimke/webmock вместо заглушки Net :: HTTP.   -  person Bartosz Blimke    schedule 30.07.2013


Ответы (3)


Вы просто не можете заглушить локальную переменную, вы можете только заглушить методы. В вашем случае вы можете заглушить метод Net::HTTP.get:

Net::HTTP.stub(:get).and_return(stub_resp)
person toro2k    schedule 30.07.2013
comment
Решено! Спасибо за быстрый ответ! - person Neeran; 30.07.2013

Не существует такой вещи, как «заглушка локальной переменной». Единственное, что можно заглушить, - это вызовы методов.

Вам понадобится заглушка вызова Net::HTTP.get, чтобы вернуть что-то похожее на Net::HTTPResponse, с которым может работать остальная часть вашего кода.

Мне довольно часто нравится убирать это, имея клиентский класс для каждого api, который знает, как генерировать URL-адрес из аргументов (в данном случае id) и как анализировать ответ. Это сохраняет эти детали вне контроллера, а также упрощает тестирование, поскольку теперь вы можете предоставить имитацию клиентского объекта.

person Frederick Cheung    schedule 30.07.2013

Вы не можете заглушить локальную переменную. Просто метод. Поскольку ответы были выше, вы можете отключить вызов Net :: HTTP.get. Однако, если вы не хотите, чтобы ваш код полагался на конкретную клиентскую библиотеку HTTP, вы можете извлечь HTTP-запрос в другой метод контроллера и заглушить этот метод.

Class UsersController < ApplicationController
...
def get_company
    resp = make_request(params[:id)
    @resp = JSON.parse(resp.body)
end

protected

def make_request(id)
  Net::HTTP.get('http://get_company_from_user_id.com/#{id}.json')
end


controller.
  should_receive(:make_request).
  with(@test_user.id).
  and_return(stub_resp)
person cryo28    schedule 30.07.2013