我已经尝试了一段时间使用webmock存根多部分请求,还没有找到一个令人满意的解决方案。
理想情况下,我希望按照如下方式存根请求:
stub_request(:post, 'http://test.api.com').with(:body => { :file1 => File.new('filepath1'), file2 => File.new('filepath2') })
然而,这似乎不起作用,RSpec抱怨请求没有存根。打印未存根的请求:
stub_request(:post, "http://test.api.com").
with(:body => "--785340rnContent-Disposition: form-data; name="file1"; filename="filepath1"rnContent-Type: text/plainrnrnhellorn--785340rnContent-Disposition: form-data; name="file2"; filename="filepath2"rnContent-Type: text/plainrnrnhello2rn--785340rn",
:headers => {'Accept'=>'*/*; q=0.5, application/xml', 'Accept-Encoding'=>'gzip, deflate', 'Content-Length'=>'664', 'Content-Type'=>'multipart/form-data; boundary=785340', 'User-Agent'=>'Ruby'}).
to_return(:status => 200, :body => "", :headers => {})
当然,我真的不能遵循这个建议,因为边界是动态生成的。知道我怎样才能正确地存根这些请求吗?
谢谢!布鲁诺
有点晚了,但我会给未来的overflowers和google用户留下答案。
我有同样的问题,并将Rack::Multipart::Parser与Webmock结合使用作为解决方案。快速和不干净的代码应该看起来像这样(警告:使用activesupport扩展):
stub_request(:post, 'sample.com').with do |req|
env = req.headers.transform_keys { |key| key.underscore.upcase }
.merge('rack.input' => StringIO.new(req.body))
parsed_request = Rack::Multipart::Parser.new(env).parse
# Expectations:
assert_equal parsed_request["file1"][:tempfile].read, "hello world"
end
WebMock目前不支持多部分请求。查看作者的评论,了解更多信息:https://github.com/vcr/vcr/issues/295#issuecomment-20181472
我建议你考虑以下途径之一:
- 不匹配post multipart body的
- 存根
- 将请求封装在带有文件路径参数的方法中,并对该方法设置更细粒度的期望
- 在集成测试中使用VCR模拟外部请求
下面是使用WebMock和regex来匹配多部分/表单数据请求的解决方案,对于测试图像上传特别方便:
stub_request(:post, 'sample.com').with do |req|
# Test the headers.
assert_equal req.headers['Accept'], 'application/json'
assert_equal req.headers['Accept-Encoding'], 'gzip, deflate'
assert_equal req.headers['Content-Length'], 796588
assert_match %r{Amultipart/form-data}, req.headers['Content-Type']
assert_equal req.headers['User-Agent'], 'Ruby'
# Test the body. This will exclude the image blob data which follow these lines in the body
req.body.lines[1].match('Content-Disposition: form-data; name="FormParameterNameForImage"; filename="image_filename.jpeg"').size >= 1
req.body.lines[2].match('Content-Type: img/jpeg').size >= 1
end
仅测试标题也可以使用使用stub_request(:post, 'sample.com').with(headers: {'Accept' => 'application/json})
的正常WebMock方式完成,并且简单地在with
子句中不包含任何正文规范。