让Rails测试意识到Rails内部链外的Rack中间件

pab*_*obm 16 testing integration integration-testing rack ruby-on-rails

上下文:应用程序使用必须在config.ru中设置的Rack中间件,而不是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
Run Code Online (Sandbox Code Playgroud)

如果您运行上述测试,一切都很好,使用浏览器,您可以确认访问路径/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
Run Code Online (Sandbox Code Playgroud)

现在,测试将停止工作.如果您/so使用浏览器访问,该功能确实有效.只是测试不知道Rack设置.

pab*_*obm 16

(感谢Dan Croak让我走上了正确的道路.这个答案完成了他所说的话).

简短的回答

无法进行功能测试.

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

ActionDispatch::IntegrationTest.app = Rack::Builder.new do
  eval File.read(Rails.root.join('config.ru'))
end
Run Code Online (Sandbox Code Playgroud)

答案很长

功能测试只是针对控制器运行的单元测试.例如get :index,当你说你没有解决路线时.相反,这是调用index方法的简写,其中包含对HTTP方法提及的请求环境为GET.

因此,您的Rack堆栈不会影响功能测试.

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

但我说"默认情况下",因为Rails提供了一种方法来改变Rack堆栈的测试.默认情况下,集成测试会调用Rails.application其请求.您可以将其更改为适合您需求的任何内容.

通过使用上面的代码,我们使用Rack::Builder创建ad-hoc Rack应用程序.在块中,您可以放置​​通常放在config.ru文件中的任何代码.为避免代码重复,请eval加载我们的config.ru文件.现在,我们的集成测试将加载与应用服务器公开的完全相同的应用程序.

  • 如果您正在使用Capybara并想要测试您的功能规格,您可以类似地执行Capybara.app = Rack :: Builder.new do eval File.read(Rails.root.join('config.ru'))end (2认同)