使用rspec在控制器中调用API调用

时间:2013-07-30 11:42:50

标签: ruby rspec stubbing

我只是有点困惑为什么我不能在我的控制器规范中存根局部变量。

这是我的控制器:

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变量?

3 个答案:

答案 0 :(得分:6)

你只是不能存根本地变量,你只能存根方法。在您的情况下,您可以存根Net::HTTP.get方法:

Net::HTTP.stub(:get).and_return(stub_resp)

答案 1 :(得分:3)

没有“存根本地变量”这样的东西。唯一可以存根的是方法调用。

您需要使用Net::HTTP.get调用的存根来返回看起来像Net::HTTPResponse的其他代码可以使用的内容。

我经常喜欢通过为每个API知道如何从参数生成url(在本例中为id)以及如何解析响应的客户端类来整理它。这样可以将这些细节保留在控制器之外,并使测试变得简单,因为现在您可以提供模拟客户端对象

答案 2 :(得分:3)

您不能存根本地变量。只是一种方法。由于上面有答案,您可能希望存根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)