Ruby on rails 使Rails测试了解Rails外部的机架中间件';内链

Ruby on rails 使Rails测试了解Rails外部的机架中间件';内链,ruby-on-rails,testing,integration,integration-testing,rack,Ruby On Rails,Testing,Integration,Integration Testing,Rack,上下文:应用程序使用必须在config.ru中设置的一段机架中间件,而不是Rails的内部中间件链。这是与这个问题无关的原因 问题:我如何让我的测试(功能和集成)意识到这个中间件 我会举个例子来说明。让我们创建一个原始的Rails 3应用程序,用于演示目的 # /config/initializers/example.rb Rails.application.middleware.insert 0, 'Rack::Rewrite' do r301 '/so', 'http://stackove

上下文:应用程序使用必须在config.ru中设置的一段机架中间件,而不是Rails的内部中间件链。这是与这个问题无关的原因

问题:我如何让我的测试(功能和集成)意识到这个中间件

我会举个例子来说明。让我们创建一个原始的Rails 3应用程序,用于演示目的

# /config/initializers/example.rb
Rails.application.middleware.insert 0, 'Rack::Rewrite' do
 r301 '/so', 'http://stackoverflow.com'
end

# /test/integration/the_test.rb
require 'test_helper'

class TheTest < ActionDispatch::IntegrationTest
 test "redirect from /so to http://stackoverflow.com" do
   get '/so'
   assert_redirected_to 'http://stackoverflow.com'
 end
end

现在,测试将停止工作。如果您使用浏览器访问
/so
,则该功能确实有效。只是测试没有意识到机架设置。

我认为问题在于
ActionDispatch::IntegrationTest
使用您的
Rails.application
作为测试的机架应用程序

因此,如果您可以将该
Rack::Rewrite
规则包装到某个机架中间件中,您应该能够用以下内容覆盖您在测试中测试的机架应用程序:

ActionDispatch::IntegrationTest.app = MyRewriteMiddleware
(谢谢Dan Croak让我走上正轨。这个答案完成了他所说的)

简短回答 无法进行功能测试

对于集成测试,请将以下内容添加到test_helper.rb中:

ActionDispatch::IntegrationTest.app = Rack::Builder.new do
  eval File.read(Rails.root.join('config.ru'))
end
长话短说 功能测试只是针对控制器运行的单元测试。例如,当您说
get:index
时,您并不是在解析路由。相反,这是调用
index
方法的简写,请求环境中包含对正在获取的HTTP方法的提及

因此,机架堆栈不影响功能测试是有意义的

集成测试是另一回事。您正在测试您的完整堆栈,因此您也需要测试机架中间件。唯一的问题是,默认情况下,这些测试只能看到您使用Rails自己的API添加的中间件

但我之所以说“默认”,是因为Rails提供了一种方法来更改要测试的机架堆栈。默认情况下,集成测试为其请求调用
Rails.application
。您可以将其更改为任何适合您需要的内容


通过使用上面的代码,我们使用
Rack::Builder
创建一个特殊的机架应用程序。在块中,您可以将通常会放入
config.ru
文件中的任何代码放入块中。为了避免代码重复,
eval
加载我们的
config.ru
文件。现在,我们的集成测试将加载与我们的应用服务器公开的应用程序完全相同的应用程序。

我如何为RSpec扩展此功能?如果您正在使用Capybara并希望在功能规格中进行测试,您可以类似地执行Capybara.app=Rack::Builder.new do eval File.read(Rails.root.join('config.ru'))endI已经尝试过Agustin针对RSpec的解决方案,我可以验证它是否有效。谢谢。@JasonSwett您是如何将此应用于Rspec的?非常感谢您的帮助
ActionDispatch::IntegrationTest.app = Rack::Builder.new do
  eval File.read(Rails.root.join('config.ru'))
end