使Rails测试了解Rails内部链外部的Rack中间件 [英] Making Rails tests aware of Rack middleware outside Rails's internal chain

查看:55
本文介绍了使Rails测试了解Rails内部链外部的Rack中间件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

上下文:应用程序使用了一部分必须在config.ru中设置的Rack中间件,而不是Rails的内部中间件链.这是由于与该问题无关的原因.

Context: an application uses a piece of Rack middleware that must be setup in config.ru, rather than Rails's internal Middleware chain. This is for reasons not relevant to this question.

问题:如何使我的测试(功能和集成)了解这种中间件?

Question: how do I make my tests (functional and integration) aware of this middleware?

我将举例说明.让我们使用机架重写创建一个原始的Rails 3应用程序.

I'll ellaborate with an example. Let's create a pristine Rails 3 app, using rack-rewrite for illustration purposes.

# /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.

If you run the above test, all is good, and with the browser you can confirm that visiting the path /so will redirect you to StackOverflow indeed.

很酷,现在让我们在Rails外部进行设置.删除上述文件/config/initializers/example.rb,然后将config.ru更改为以下内容:

Cool, let's now set this up outside Rails then. Remove the file /config/initializers/example.rb described above, and change config.ru to the following:

# /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,则该功能确实起作用.只是测试不知道该机架设置.

Now, the test will stop working. The functionality does work, as evidenced if you visit /so with your browser. It's only that the tests are not aware of that Rack setup.

推荐答案

(感谢Dan Croak将我设置在正确的轨道上.此答案完成了他的发言).

(Thanks Dan Croak for setting me on the right track. This answer completes what he said).

无法进行功能测试.

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

For integration tests, add the following to your test_helper.rb:

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

长答案

功能测试只是针对控制器运行的单元测试.例如,当您说get :index时,您并没有解析路径.相反,这是调用index方法的简写,请求环境包括对HTTP方法的提及(即GET).

Long answer

Functional tests are just unit tests run against controllers. When you say, for example get :index, you are not resolving a route. Instead, this is a shorthand for calling the index method, with a request environment that includes a mention to the HTTP method being GET.

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

Therefore, it makes sense that your Rack stack does not influence functional tests.

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

Integration tests are a different matter. You are testing your full stack there, so you will want to test your Rack middlewares too. Only problem is that, by default, these tests only see the middlewares that you add using Rails's own API.

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

But I say "by default" because Rails offers a way to change what Rack stack will be tested. By default, integration tests call Rails.application for their requests. You can change this to anything that suits your needs.

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

By using the code above, we use Rack::Builder create an ad-hoc Rack application. Inside the block, you can put any code that you would normally put inside a config.ru file. To avoid code duplication, eval loads our config.ru file. Now our integration tests will load exactly the same application that our app servers expose.

这篇关于使Rails测试了解Rails内部链外部的Rack中间件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆