在没有服务器的情况下测试 Ruby Rack 时,如何伪造上传文件?

Ali*_*urn 4 ruby rack functional-testing

为了测试,我将 Rack::Request 直接发送到应用程序,而不是使用服务器。

def request_via_API( app, method, path, params={} ) # app should be API
  env = Rack::MockRequest.env_for( path, {:method => method, :params=>params}  )
  app.handle Rack::Request.new(env)
end
Run Code Online (Sandbox Code Playgroud)

非常适合测试直接输入,但我被文件上传所困扰。我的真实系统通过文件上传在浏览器中运行良好。但是现在我想通过 API 对其进行测试,并且不知道如何通过任何 Rack 类/方法将文件内容放入请求中。(我尝试理解 Rack::Test::UploadedFile 但没有成功)。

谢谢,阿利斯泰尔

frz*_*zng 5

你绝对是在正确的道路上。您甚至可以在request_via_API不进行任何修改的情况下使用您的函数,例如:

request_via_API(app, 'POST', '/', {
  :field => "value",
  :text_source => Rack::Multipart::UploadedFile.new(PATH_TO_YOUR_FILE, MIME_TYPE_OF_YOUR_FILE)
})
Run Code Online (Sandbox Code Playgroud)

这意味着您需要在某处放置一些文件。如果您使用夹具,您的测试上传文件应该围绕它们。您可以省略 MIME 时间,但默认为text/plain.

如果您使用准系统 Rack,您会在调用后得到以下哈希值Rack::Multipart.parse_multipart

{
  "field" => "value",
  "text_source" => {
    :filename => File.basename(PATH_TO_YOUR_FILE),
    :type => MIME_TYPE_OF_YOUR_FILE,
    :name => "text_source",
    :tempfile => Tempfile.new("RackMultipart"), # copied from PATH_TO_YOUR_FILE
    :head => "Content-Disposition: form-data; name=\"text_source\"; filename=\"#{File.basename(PATH_TO_YOUR_FILE)}\"\r\n" +
             "Content-Type: #{MIME_TYPE_OF_YOUR_FILE}\r\n" +
             "Content-Length: #{BYTESIZE_OF_YOUR_FILE}\r\n"
  }
}
Run Code Online (Sandbox Code Playgroud)

当然,text_source密钥可以有任何其他名称。

Rack::MockRequest#env_for 如果出现以下情况,将自动尝试创建多部分表单数据请求:

  • HTTP 方法不是 GET
  • 没有:input提供选项
  • :params 选项是一个 Hash
  • :params 选项值至少包含一个实例 Rack::Multipart::UploadedFile

您可以在此处此处查看源代码中的详细信息。

我认为依赖于多部分请求生成,Rack::MockRequest并且Rack::Multipart仅用于模拟具有相同文件上传和文件上传机制的 HTML 表单。所以,没有必要直接使用Rack::Multipart#build_multipartor Rack::Multipart::Generator

如果您有更复杂的多部分场景或不同的文件上传机制,则必须opts使用:inputkey 而不是:paramsto传递参数Rack::MockRequest#env_for:input就机架模拟功能而言,如何为其生成该值是您的问题。只有StringIO当它是 a时才会将其包裹起来,String正如您在此处看到的那样。否则,它将与rack.input在 Rack 环境散列中传递的内容相同,因此它必须符合Rack 输入流规范(即,是一个IO类似对象)。

因为这对我来说也是一个很大的挑战,我用它作为练习来加深我对 Rack 的了解,所以我在 GitHub 上创建了一个简单的项目来探索这个文件上传模拟。

注意:我尝试将所有内容修复到 Rack 1.5.2,除了到 Rack SPEC 的链接(所以要小心)。指向 Ruby StdLib 的链接指向当前版本。