在Rails 3中测试子域约束的​​路由

问题描述

| 我正在使用Test :: Unit测试我的Rails应用程序。我经常遇到的一个问题是测试我的应用程序的路由,但尚未找到解决方案。 目前,我正在开发一个使用Basecamp样式子域来区分帐户的应用程序。 有些路线需要一个子域
constraints(SubdomainRoute) do
  get  \"/login\" => \"user_sessions#new\",:as => :login
  get  \"/logout\" => \"user_sessions#destroy\",:as => :logout
  ...
end
以及只能在没有子域的情况下访问的路由
constraints(NoSubdomainRoute) do
  match \"/\" => \"public#index\",:as => :public_root
  match \"/signup\" => \"public#signup\",:as => :signup
  ...
end
SubdomainRoute类的定义为:
class SubdomainRoute
  def self.matches?(request)
    request.subdomain.present? && request.subdomain != \"api\" && request.subdomain != \"www\"
  end
end
NoSubdomainRoute类几乎相反。 路由按预期工作,但是如何使用Test :: Unit测试那些路由? 在功能测试中,我可以做类似的事情
assert_routing \"/signup\",:controller => \"public\",:action => \"signup\"
但我无法提供子域,因此实际上,这仅是测试Rails内部结构,因此对测试我的应用程序没有任何作用。在这种情况下,我想测试的是无论有没有子域都可以访问signup_path / signup_url。 在代码中,像这样
assert_raise(Actiondispatch::RoutingError) { get \"http://account.test.host/signup\" }
get \"http://www.test.host/signup\"
assert_response :success
get在这种情况下不起作用,因为Test :: Unit将整个URL视为控制器的操作(...:action => \“ http://account.test.host/signup \”)。 设置
@request.host = \"subdomain.test.host\"
仅会影响您的内部控制器代码(例如,通过从主机提取子域来获得经常帐户),但在这种情况下不会影响路由。 我不知道集成测试中的情况是否有所不同。 所以两个主要问题是 一般而言,路线在哪里意味着睾丸? 他们如何测试这种特殊情况? 我愿意尝试不同的方法(Capybara和朋友),但是我不想切换测试框架(已经有了RSpec-time),因为我对Test :: Unit非常满意。 在此先感谢您的光临!     

解决方法

        实际上,解决方案非常简单,因为ѭ6确实支持URL:
assert_routing \"http://subdomain.example.com/login\",{ :controller => \"user_sessions\",:action => \"new\" }

assert_routing \"http://www.example.com/signup\",{ :controller => \"public\",:action => \"signup\" }
在此处添加了提供指向assert_routing URL的功能。 搜索策略: 发现
assert_routing
actionpack
中定义
gem install gemedit
gem edit actionpack
打开
lib/action_dispatch/testing/assertions/routing.rb
,发现ѭ13path是处理路径处理的内容 通过GitHub打开文件,然后选择\'Blame \'以查看哪个提交添加了该功能     ,        我发现rr是测试子域和自定义域的最佳方法。例如,我有一个可处理自定义域的机架应用。这是一个示例测试:
require File.join(File.dirname(__FILE__),\'..\',\'test_helper\')
require \'rr\'
require \'custom_domain\'
require \'rack/test\'

class CustomDomainTest < ActiveSupport::TestCase
  include Rack::Test::Methods
  include RR::Adapters::TestUnit

  def app
    Rails.application
  end

   def test_cname_to_subdomain
     mock(CustomDomain::Cname).resolver(\'www.example.com\',\'.lvh.me\') { \'subdomain.lvh.me\' }
     get \'http://www.example.com:80/users\'
     assert_equal \'www.example.com,subdomain.lvh.me:80\',last_request.env[\'HTTP_X_FORWARDED_HOST\']
     assert_equal \'www.example.com\',last_request.env[\'SERVER_NAME\']
     assert_equal \'www.example.com\',last_request.env[\'X_CUSTOM_CNAME\']
     assert_equal \'subdomain.lvh.me\',last_request.env[\'X_CUSTOM_SUBDOMAIN\']

   end
 end
end
这里有一些讨论此主题的链接,您可能会发现有用: http://www.brynary.com/2009/3/5/rack-test-released-a-simple-testing-api-for-rack-based-frameworks-and-apps http://effectif.com/articles/testing-rails-with-rack-test http://gitrdoc.com/brynary/rack-test/tree/master http://github.com/brynary/rack-test http://jasonseifer.com/2009/04/08/32-rack-resources-to-get-you-started http://guides.rubyonrails.org/rails_on_rack.html http://rack.rubyforge.org/doc/SPEC.html 祝好运。     ,        我寻找了非艰难的方法来修补路由测试机制,但没有找到任何方法。 我最终只是解决了约束的匹配?方法:
describe ThingsController do

  shared_examples_for \"a subdomain route\" do |http_method,path,expected_action|
    context(\"on a subdomain\") do
      before do
        stub(SubdomainRoute).matches? { true }
        stub(NoSubdomainRoute).matches? { false }
      end
      it { should route(http_method,path).to(:action => expected_action) }
    end

    context(\"on the main domain\") do
      before do
        stub(SubdomainRoute).matches? { false }
        stub(NoSubdomainRoute).matches? { true }
      end
      it { should_not route(http_method,path).to(:action => expected_action) }
    end
  end

  it_should_behave_like \"a subdomain route\",:get,\'/things/new\',:new

...
(我正在使用rspec和rr。我想将路由测试放在控制器规范中,就在动作的describe块之前。共享的示例将移至混入控制器规范的模块中。)     ,        为了使约束在开发模式下运行,我向ENV哈希添加一个值,如下所示启动服务器:
site=trivial.ly ruby script/rails server
在这里,我传递了整个域,您可以传递一个子域。然后在约束类中,我检测到域或ENV [:site]值,如下所示:
class DomainConstraint
  def initialize(domain)
    @domains = [domain].flatten
  end

  def matches?(request)
    @domains.include?(request.domain) || @domains.include?(ENV[\"site\"])
  end
end
现在,测试具有特定约束的控制器仅是像这样设置正确的ENV [:site]值(在test :: unit中)的问题:
require \'test_helper\'

class TrivialLy::SplashPagesControllerTest < ActionController::TestCase
  test \"should get android splash page\" do
    ENV[\"site\"] = \"trivial.ly\"
    get :android
    assert_response :success
  end
end
这适用于域约束,也适用于子域约束。     ,        这些其他答案都不能回答这个问题,至少不能以任何优雅的方式。不需要假装。 要在Rails集成测试中使用Rails 3子域约束:只需在集成测试中将域作为请求的一部分包括在内:
get \"http://admin.example.com/dashboard\"
我在以下路线上(几乎)成功地对此进行了测试,没有任何问题:
scope :admin,as: \'admin\',module: \'admin\' do
  constraints subdomain: \'admin\' do
    resource \'dashboard\',controller: \'dashboard\'
  end
end
询问者可能没有使用集成测试,也没有使用过旧版本的Rails。     ,        我自己是@ RoR3的新用户,但也许该截屏视频可以帮助您:Railscasts子域     ,我将测试您的类的功能,而不必测试路由本身。我觉得这实际上是测试滑轨。 您知道,如果您将类传递给constraints块,那么在定义了.matches的情况下它将起作用。方法。因此,只需测试您是否已达到预期的逻辑即可。     ,        正如马特·波利托(Matt Polito)所说,测试您想要发生的事情。 在您的约束中,您必须具有某种before_filter或某种可以处理某人不应该在原地的情况的东西。甚至像ѭ21一样,您必须通过重定向和Flash警告来处理这种情况,以便可以对此进行测试。 甚至在子域名的情况下,我在带有子域名的邮件程序中分配了一个变量。我在测试中检查的是该变量,例如:
setup do
  #  get_sub is just @request.host = \"#{sub}.local.me\" in test_helper.rb
  get_sub(\"two\") 
  @deal = deals(:two)
end
test \"should get show\" do
  get :show,:token => @deal.token
  assert_response :success
  [\"deal\",\"subdomain\",\"user_profile\"].each do |variable|
    assert assigns[variable.to_sym],\"I can\'t find a var called #{variable}\"
  end
end
因此测试我想要的任何东西都可以通过,并且通过了潜艇。在您的情况下,我认为应该只是/ login响应:success。     ,        Rails 3中的子域非常简单,只需将其放置为:
constraints :subdomain => subdomain_name do
  #here comes all routes which routes under above subdomain
end