Тестирование маршрутов с ограниченным поддоменом в Rails 3 - PullRequest
20 голосов
/ 12 июня 2011

Я тестирую свои приложения на Rails с Test :: Unit.Проблема, с которой я часто сталкиваюсь, - это тестирование маршрутов моего приложения, для которых я еще не нашел решения.

В настоящее время я работаю над приложением, которое использует субдомены в стиле 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"

влияет только на код вашего внутреннего контроллера (например, получение текущей учетной записи)путем извлечения субдомена из хоста), но не влияет на маршрутизацию в этом случае.

Я не знаю, отличается ли ситуация в интеграционных тестах.

Таким образом, два основных вопроса

  1. Где - маршруты, которые должны быть проверены в целом?
  2. Как они проверяются в отношении этого особого случая?

Я собираюсь опробовать разные подходы (Capybara и друзья), но я не хочу переключать свою среду тестирования (у меня уже было время RSpec), так как в остальном я очень доволен Test :: Unit.

Заранее спасибо и кс уважением!

Ответы [ 9 ]

13 голосов
/ 10 августа 2012

На самом деле решение очень простое, так как 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" }

Добавлена ​​возможность предоставления URL для assert_routing здесь .

Стратегия поиска:

  • Найдено assert_routing было определено в actionpack
  • gem install gemedit
  • gem edit actionpack
  • Открыт lib/action_dispatch/testing/assertions/routing.rb и найден recognized_request_for - это то, что обрабатывает обработку пути
  • Открыл файл через GitHub и выбрал «Blame», чтобы увидеть, какой коммит добавил эту функциональность
2 голосов
/ 16 декабря 2011

Я искал нехорошие способы подключения к оборудованию для тестирования маршрутов и не нашел ни одного.

Я закончил тем, что просто потушил соответствие ограничений?методы:

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. Мне нравится помещать тесты маршрутов в спецификации моего контроллера, непосредственно перед описанием блоков для действий. Общие примеры будут перемещены в модуль, который смешиваетсяв спецификации контроллера.)

2 голосов
/ 16 декабря 2011

Я обнаружил, что 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

А вот несколько ссылок на эту тему, которые могут оказаться полезными для вас:

Удачи.

1 голос
/ 25 июля 2013

Ни один из этих других ответов не отвечает на вопрос, по крайней мере, не элегантно. Насмешки не нужны.

Чтобы использовать ограничения поддоменов Rails 3 в интеграционном тесте Rails: просто включите домен как часть запроса в интеграционный тест:

get "http://admin.example.com/dashboard"

Я успешно проверил это на (в значительной степени) следующем маршруте, без проблем:

scope :admin, as: 'admin', module: 'admin' do
  constraints subdomain: 'admin' do
    resource 'dashboard', controller: 'dashboard'
  end
end

Возможно, спрашивающий не использовал интеграционные тесты или более старую версию Rails.

1 голос
/ 20 сентября 2012

Чтобы мои ограничения работали в режиме разработки, я добавляю значение в хеш 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

Это работает для ограничений домена, оно будет одинаково хорошо работать для ограничений поддоменов.

0 голосов
/ 31 октября 2011

Субдомены в rails 3 очень просты: просто ставится:

constraints :subdomain => subdomain_name do
  #here comes all routes which routes under above subdomain
end
0 голосов
/ 16 июля 2011

Как сказал выше Мэтт Полито, проверь, что ты хочешь, чтобы произошло.

В ваших ограничениях у вас должен быть какой-то before_filter или что-то, что обрабатывает случай, когда кто-то не должен быть там, где он есть. или даже как www.yourdomain.com/login, вы должны справиться с этой ситуацией с помощью перенаправления и мгновенного предупреждения, чтобы вы могли проверить это.

даже в моем случае для поддоменов я назначил переменную в почтовой программе с поддоменом. Именно эту переменную я проверил в своем тесте, например:

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, я думаю.

0 голосов
/ 09 июля 2011

Я бы протестировал функциональность вашего класса не обязательно сам маршрут.Я чувствую, что это по сути тестирование rails.

Вы знаете, что если вы передадите свой класс в блок ограничений, он сработает, если вы определили .matches?метод.Так что просто проверьте, что вы получаете ожидаемую логику там.

0 голосов
/ 17 июня 2011

Я сам новенький @ RoR3, но, возможно, вам поможет эта скринкаст: Субдомен Railscasts

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...