我在尝试围绕rails控制器编写测试时遇到了一个非常奇怪的问题。
控制器使用RestClient
从另一台服务器获取信息。如果第二个服务器返回错误响应,我想将该错误消息转发给客户端。
控制器:
def callback_submit
begin
response = RestClient.post(...)
render json: response
rescue RestClient::BadRequest => e
render status: :bad_request, json: { error: e.response.body }
end
end
然后我对此进行了一次rspec测试:
it 'returns a failure message' do
stub_request( :post, 'http://...' ).to_return( status: 400, body: 'some error' )
post :callback_submit
expect(response.body).to eq({error: 'some error'}.to_json)
end
现在的问题是rspec输出是:
expected: "{\"error\":\"some error\"}"
got: "{\"error\":\"\"}"
奇怪的是,我可以将控制器更改为puts
一些细节......
rescue RestClient::BadRequest => e
error = e.response.body.to_s
puts error.class
puts error
render status: :bad_request, json: { error: error }
哪个输出:
String
some error
expected: "{\"error\":\"some error\"}"
got: "{\"error\":\"\"}"
所以error
变量似乎是一个字符串和正确的值,但是render
将它变成一个空字符串。
现在它变得非常奇怪......如果我插入字符串:
rescue RestClient::BadRequest => e
error = e.response.body.to_s
puts error.class
puts error
render status: :bad_request, json: { error: "#{error}" }
或者只是简单地说:
rescue RestClient::BadRequest => e
render status: :bad_request, json: { error: "#{e.response.body}" }
然后我的测试通过了!
起初我以为e.response.body
不能是字符串,这就是为什么我puts
其class
打印“字符串”并在其上调用.to_s
,但是这似乎没有任何改变。
任何人都可以解释这种奇怪的行为吗?
答案 0 :(得分:3)
问了一些Ruby朋友,其中一个发现了问题,但是不想在这里发布答案....
问题最终导致我们处于较早的RestClient
(1.8)。 In the RestClient 2.0 notes:
响应对象现在是String的子类,而不是混合在响应功能中的String。
Response#body和#to_s现在将返回一个真正的String对象而不是self。以前没有简单的方法来获取真正的String响应,而不是混合了AbstractResponse的Frankenstein响应字符串对象。
所以在我使用的旧版本中,e.response
最终成为了这个奇怪的String mixin mashup,render
似乎不喜欢它。
插值再次将其转换为真正的Ruby字符串。
答案 1 :(得分:0)
问题是response.body
正在查看响应对象,并且由于错误,正文为空。
您可能需要e.message
或仅e.to_s
这将是错误消息(或错误类名称)而不是响应正文。
摘录:
class Exception < RuntimeError
attr_accessor :response
attr_writer :message
#.......
def to_s
message
end
def message
@message || default_message
end
def default_message
self.class.name
end
end