如何让Rspec的class_double每次调用返回不同REST响应
解决Rspec中多次REST调用返回不同模拟响应的问题
我需要用Rspec测试Device类,其中涉及对Request类和HTTPI模块的模拟,返回REST响应。当前单次调用能正常工作,但当方法发起第二次REST调用时,需要返回新的响应,这个需求还没实现。
相关代码
API类(简化版本,核心逻辑完整)
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类(调用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} # 我知道这会导致HTTPI.send始终返回相同的resp,但没有它测试甚至无法完成第一次调用 let!(:http) {class_double('HTTPI', send: resp).as_stubbed_const} it 'test' do Device.get_device end end
期望效果:让模拟的HTTPI.send第一次调用返回resp,第二次返回resp2。
解决方案
要实现多次调用返回不同值,你需要用Rspec的and_return方法指定调用序列的返回结果,同时调整HTTPI的double设置:
修改测试文件中的double定义,把固定返回resp改成按顺序返回resp和resp2:
Rspec.describe Device do let(:resp) { {code: 200, body: resp_body, raw_body: "TEST BODY", cookies: [cookie_list_hash]} } let(:resp2) { {code: 200, body: resp_body_2, raw_body: "TEST BODY 2", cookies: [cookie_list_hash]} } # 模拟Request类 let!(:request_double) { class_double('Request').as_stubbed_const } # 模拟HTTPI模块 let!(:httpi_double) { class_double('HTTPI').as_stubbed_const } it 'returns different responses for multiple API calls' do # 指定HTTPI.send按调用顺序返回不同响应 expect(httpi_double).to receive(:send) .and_return(resp, resp2) # 注意:如果get_device是实例方法,需要先创建Device实例 device = Device.new device.get_device end end
关键说明
expect(httpi_double).to receive(:send).and_return(resp, resp2)可以让HTTPI.send按调用顺序依次返回指定响应。- 无需将Request的new方法绑定到HTTPI的double,测试重点是HTTPI的返回结果,只要Request类被正确模拟占位即可。
- 将
resp和resp2改为let定义,确保它们在测试上下文里正确初始化,避免作用域问题。
另外,你的Device类中get_device是实例方法,调用时必须先创建Device实例;如果要作为类方法调用,需要修改Device类:
class Device @api = API.new(:open_timeout => 30, :read_timeout => 30) def self.get_device devices = @api.find_device(@id) log.info("First Call Made") other_call = @api.find_other_device(@other_id) end end
内容的提问来源于stack exchange,提问作者Ryan Burch
相关产品推荐
相关产品推荐

