我有一个RSpec测试,它需要将RequestHTTPI类/模块加倍,并返回一个模拟的REST响应.在此方法进行另一次REST调用并需要返回新的REST响应之前,我一直在使用该方法.

API Class
NOTE this is a trimmed down version of the class but the gist is there

class API
  include HTTPI
  
  def find_device(id)
    req = create_request('path')
    req.body = { :customerId => MultiJson.dump(customer_id) }
    return call(req)
  end
  
  def find_other_device(other_id)
    req = create_request('path')
    req.body = { :other_id => MultiJson.dump(other_id) }
    data = call(req)
    return data
  end
  
  def call(req)
    response = HTTPI.send(req)
    return response.body
  end
end

装置 文件调用REST方法

class Device
  @api = API.new(:open_timeout => 30, :read_timeout => 30)
  def get_device
    devices = @api.find_device(@id)
    log.info("First Call Made")
    other_call = @api.find_other_device(@other_id)
  end
end

等级库文件

Rspec.describe Device do
  resp = {code: 200, body: resp_body, raw_body: "TEST BODY", cookies: [cookie_list_hash]}
  resp2 = {code: 200, body: resp_body_2, raw_body: "TEST BODY 2", cookies: [cookie_list_hash]}
  let!(:request) {class_double('Request', new: http).as_stubbed_const} # I understand this causes the HTTPI send request to always return the same resp, but without it the test does not even get past the first call
  let!(:http) {class_double('HTTPI', send: resp).as_stubbed_const}

  it 'test' do
    Device.get_device
  end
end

我们希望创建一个双精度函数,首先返回resp var,然后在第二次调用:end时返回res2.

我也是Ruby的新手,所以这可能会很难看.

推荐答案

我将重点放在您的规范上,尽管您的其他类中可能还有一些其他内容需要复习(取决于您想要实现的目标). 也许如果你用另一种方式写它,你就能理解它背后的逻辑. 首先,您还需要将响应定义为let;此外,您还可以查看returning different values across multiple calls.

Rspec.describe Device do
  let(:resp) do 
    {
      code: 200, body: resp_body, raw_body: "TEST BODY", cookies: [cookie_list_hash]
    }
  end
  let(:resp2) do
    {
      code: 200, body: resp_body_2, raw_body: "TEST BODY 2", cookies: [cookie_list_hash]
    }
  end
  let!(:request) { class_double('Request', new: http).as_stubbed_const }
  let!(:http) { class_double('HTTPI').as_stubbed_const }

  before do
    # see https://www.rubydoc.info/github/rspec/rspec-mocks/RSpec%2FMocks%2FMessageExpectation:and_return
    allow(http).to receive(:send).and_return(resp, resp2)
  end

  it 'test' do
    Device.get_device
  end
end

话虽如此,这可能会解决您的规范的问题,但似乎您也希望您的api对象是一个实例变量,而不是在您的类中定义的东西:

class Device
  def api
    # This will create the API object only once, and return it each time you call it in #get_device
    @api ||= API.new(:open_timeout => 30, :read_timeout => 30)
  end

  def get_device
    devices = api.find_device(@id)
    log.info("First Call Made")
    other_call = api.find_other_device(@other_id)
  end
end

但是,再说一次,这取决于您想要实现什么,以及您粘贴的代码是否完整/正确,如果这不适用,非常抱歉.

Ruby相关问答推荐

带有(*)签名的Ruby方法

Ruby 3 从多个预定纤程中收集结果

我可以在 Ruby 的 heredoc 中访问变量吗?

需要在Ruby中将数组拆分为指定大小的子数组

我如何判断哪些模块已混合到一个类中?

如何增加 ruby​​ 应用程序的堆栈大小.递归应用程序获取:堆栈级别太深(SystemStackError)

如何在不按 Enter 的情况下获取单个字符?

ruby命令在我的 Mac 上没有任何作用

Ruby代码美化,多行拆分长指令

从 Ruby 中的 DateTime 中减go n 小时

如何引用全局变量和类变量?

读取文件时如何避免 UTF-8 BOM

使用 for each 时识别最后一个循环

不区分大小写的数组#include?

什么是匹配不在行尾的字符串的正则表达式?

ruby 中&:运算符的功能是什么?

在ruby中将字符串转换为十进制数

如何在 Ruby 中找到字符串中字符的索引?

如何删除已安装的 ri 和 rdoc?

直接访问实例变量与使用访问器方法