我有一个 Rspec 测试需要将
Request
和 HTTPI
类/模块加倍并返回一个模拟的 REST 响应。我有这个工作,直到这个方法进行另一个 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
设备 文件调用 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
希望做一个 double,首先返回 resp var,然后在第二次调用 :send 时返回 resp2。
我对红宝石也很陌生,所以这可能很难看。
我会专注于你的规范,尽管你的其他课程中还有一些其他的东西可能需要复习(取决于你想要达到的目标)。 也许如果您以另一种方式编写它,您可以了解其背后的逻辑。 首先,您还需要将响应定义为
let
s;另外,你可以看看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
但是,同样,这取决于您想要实现的目标以及您粘贴的代码是否完整/正确,如果这不适用,我们深表歉意。