繁体   English   中英

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

[英]Testing subdomain constrained routes in 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

class SubdomainRoute 定义为:

class SubdomainRoute
  def self.matches?(request)
    request.subdomain.present? && request.subdomain != "api" && request.subdomain != "www"
  end
end

class 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"

仅对您的内部 controller 代码有影响(例如,通过从主机中提取子域来获取当前帐户),但在这种情况下不影响路由。

我不知道集成测试中的情况是否有任何不同。

所以两个主要问题是

  1. 一般来说,路线在哪里是 testet?
  2. 他们如何针对这种特殊情况进行测试?

我愿意尝试不同的方法(Capybara 和朋友),但我不想切换我的测试框架(已经有了我的 RSpec-time),因为我对 Test::Unit 非常满意。

在此先感谢和亲切的问候!

实际上解决方案非常简单,因为assert_routing确实支持 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 ,发现recognized_request_for是处理路径处理的
  • 通过 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

以下是一些讨论此主题的链接,您可能会觉得有用:

祝你好运。

我寻找了修补路由测试机器的非糟糕方法,但没有找到任何方法。

我最终只是消除了约束的匹配? 方法:

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。我喜欢将路由测试放在我的 controller 规范中,就在操作的描述块之前。共享示例将移至混合到 Z594C103F2C603E04C3D8ABE059C 规范中的模块。)

为了使我的约束在开发模式下运行,我向 ENV hash 添加了一个值,像这样启动服务器:

site=trivial.ly ruby script/rails server

在这里,我传递了整个域,您可以改为传递一个子域。 然后在我的约束 class 中,我检测到域或 ENV[:site] 值,如下所示:

class DomainConstraint
  def initialize(domain)
    @domains = [domain].flatten
  end

  def matches?(request)
    @domains.include?(request.domain) || @domains.include?(ENV["site"])
  end
end

使用特定约束测试 controller 现在只需设置正确的 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 Subdomain

我会测试您的 class 的功能,不一定是路线本身。 我觉得这本质上是在测试轨道。

您知道,如果您将 class 传递给约束块,如果您定义了.matches,它将起作用? 方法。 因此,只需测试您是否获得了预期的逻辑。

正如上面的 matt Polito 所说,测试你想要发生的事情。

在您的约束中,您必须有某种 before_filter 或处理某人不应该在他们所在位置的情况的东西。 甚至像www.yourdomain.com/login一样,您必须通过重定向和 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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM