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

在没有服务器的情况下测试Ruby Rack时,如何假装上传文件?,ruby,rack,functional-testing,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 非常适合测试直接输入

为了进行测试,我直接向应用程序发送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
非常适合测试直接输入,但是我被文件上传所阻碍。我的真实系统通过浏览器上传文件运行良好。但是现在我想通过API测试它,不知道如何通过任何Rack类/方法将文件内容放入请求中。(我试图理解Rack::Test::UploadedFile,但没有成功)


谢谢,阿利斯泰尔

你走的路肯定是对的。您甚至可以通过_API使用您的函数请求_,无需任何修改,例如:

通过API请求(应用程序“POST”和“/”{
:field=>“value”,
:text\u source=>Rack::Multipart::UploadedFile.new(指向您的\u文件的路径,MIME\u类型\u您的\u文件)
})
这意味着你需要在某个地方有一些文件。如果您使用fixture,您的测试上传文件应该在fixture周围。可以省略MIME时间,但默认为
text/plain

如果使用barebones机架,则在调用
Rack::Multipart.parse_Multipart
后会得到以下哈希值:

{
“字段”=>“值”,
“文本_源”=>{
:filename=>File.basename(指向您的文件的路径),
:type=>MIME\u类型\u您的\u文件,
:name=>“文本\源”,
:tempfile=>tempfile.new(“RackMultipart”),#从路径_复制到_文件
:head=>“内容处理:表单数据;名称=\“文本\源\”文件名=\“{File.basename(指向您的\文件的路径)}\”\r\n+
“内容类型:{MIME\u Type\u您的\u文件的\u}\r\n”+
“内容长度:{BYTESIZE_OF_YOUR_FILE}\r\n”
}
}
当然,
text\u source
键可以有任何其他名称

在以下情况下,自动尝试创建多部分表单数据请求:

  • 无法获取HTTP方法
  • 没有提供
    :输入
    选项
  • :params
    选项是一个
    散列
  • :参数
    选项值至少包含一个
您可以在源代码和中看到详细信息

我认为通过
Rack::MockRequest
Rack::multipart
生成多部分请求只对模拟具有文件上传和文件上传机制的HTML表单有用。因此,无需直接使用
Rack::Multipart#build_Multipart
Rack::Multipart::Generator

如果您有更复杂的多部分方案或不同的文件上载机制,则必须使用
:input
键而不是
:params
opts
参数传递给。就机架模拟功能而言,如何为
:输入生成该值是您的问题。如您所见,只有当它是一个
字符串时,它才会将其封装。否则,它将作为机架环境哈希中的
rack.input
传递,因此它必须符合(即是类似
IO
的对象)

因为这对我来说也是一个很大的挑战,我把它作为一个练习来加深我对Rack的了解,我创建了一个框架来探索这个文件上传模拟


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

只需使用Rack::Test::UploadedFile.new,它将在需要时使用多部分类。好吧,它对Alistair不起作用,我发现这样做没有用,因为Rack已经具备模拟文件上传和多部分请求的功能。测试gem肯定是有用的,但是,在我看来,在这个简单的小案例中不是这样的。