使Rails测试能够感知Rails内部链之外的Rack中间件

17
背景: 应用程序使用了一段Rack中间件,必须在config.ru中进行设置,而不是Rails内部中间件链。这是由于本问题无关的原因。 问题: 如何使我的测试(功能和集成)了解此中间件?
我将通过一个示例进行说明。让我们创建一个全新的Rails 3应用程序,使用rack-rewrite来举例说明。
# /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确实会将您重定向到StackOverflow。
很酷,现在让我们在Rails之外设置它。删除上面描述的文件/config/initializers/example.rb,并将config.ru更改为以下内容:
# /config.ru
require ::File.expand_path('../config/environment',  __FILE__)

map '/so' do
  run Rack::Rewrite do
    r301 '', 'http://stackoverflow.com'
  end
end

map '/' do
  run Deleteme::Application
end

现在,测试将停止工作。如果您使用浏览器访问/so,功能确实可行。只是测试不知道Rack设置的情况。

2个回答

17

感谢 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 方法为 GET 的提及。

因此,您的 Rack 栈不会影响功能测试是有道理的。

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

但我说“默认情况”是因为Rails提供了一种改变将要测试的Rack堆栈的方法。默认情况下,集成测试会为其请求调用 Rails.application。您可以更改此设置以适应您的需求。

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


1
我该如何扩展这个以适用于RSpec? - Paulo Casaretto
2
如果您正在使用Capybara并希望在功能规范中进行测试,则可以类似地执行Capybara.app = Rack :: Builder.new do eval File.read(Rails.root.join('config.ru')) end - Agustin
我已经尝试了Agustin的RSpec解决方案,可以证实它是有效的。谢谢。 - Jason Swett
@JasonSwett 你是如何将这个应用到 Rspec 的?在这里寻求帮助,将不胜感激。 - Andrey Deineko

4

我认为问题在于ActionDispatch::IntegrationTest将你的Rails.application用作测试的Rack应用程序。

因此,如果你能将那个Rack::Rewrite规则包装成一些Rack中间件,你就可以在测试中覆盖正在测试的Rack应用程序:

ActionDispatch::IntegrationTest.app = MyRewriteMiddleware

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接