Ruby Rspec类双重返回每次调用的新REST响应。

huangapple go评论66阅读模式
英文:

Ruby Rspec class_double that returns new REST response each call

问题

I understand your request. Here's the translated code without the comments and non-translatable parts:

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

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 }
  let!(:http) { class_double('HTTPI', send: resp).as_stubbed_const }

  it 'test' do
    Device.get_device
  end
end

Please note that I've removed the HTML entities (e.g., ") and corrected some symbols for clarity. If you have any specific questions or further translations, feel free to ask.

英文:

I have a Rspec test which needs to double the Request and HTTPI class/module and return a mocked REST response. I have this working, until this method makes another REST call and needs to return a new REST response.

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

Device
file calling REST method

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

spec file

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

The hope is to make a double that returns the resp var first and on the second call the :send, it returns resp2.

I am rather new to ruby also, so this may be pretty ugly.

答案1

得分: 2

I will focus on your spec, though there are some other things in your other classes that may need review (depending on what you want to achieve).

也许如果你以另一种方式编写它,你可以理解它的逻辑。

First of all, you need to define the responses as lets as well; also, you can take a look at returning different values across multiple calls.

首先,你也需要将响应定义为 let,并且你可以查看在多次调用中返回不同的值

Having said that, which may resolve the problem with your spec, it seems that you also may want your api object to be an instance variable, and not something defined in your class:

话虽如此,这可能会解决你的规范问题,但看起来你也可能希望你的 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

But, again, this depends on what you want to achieve and if the code you pasted is complete/correct or not, so sorry if this doesn't apply.

但是,再次强调,这取决于你想要实现什么,以及你粘贴的代码是否完整/正确,所以如果这不适用的话,我很抱歉。

英文:

I will focus on your spec, though there are some other things in your other classes that may need review (depending on what you want to achieve).
Maybe if you write it another way you can get the logic behind it.
First of all, you need to define the responses as lets as well; also, you can take a look at 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

Having said that, which may resolve the problem with your spec, it seems that you also may want your api object to be an instance variable, and not something defined in your class:

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

But, again, this depends on what you want to achieve and if the code you pasted is complete/correct or not, so sorry if this doesn't apply.

huangapple
  • 本文由 发表于 2023年4月20日 08:05:13
  • 转载请务必保留本文链接:https://go.coder-hub.com/76059637.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定