我正在用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时间),因为我对Test :: Unit非常满意。 / p>
提前致谢,亲切的问候!
答案 0 :(得分:13)
实际上解决方案非常简单,因为assert_routing
支持网址:
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提供网址的能力已添加here。
搜索策略:
assert_routing
已在actionpack
gem install gemedit
gem edit actionpack
lib/action_dispatch/testing/assertions/routing.rb
,发现recognized_request_for
处理路径处理答案 1 :(得分:2)
我发现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
以下是一些讨论此主题的链接,您可能会觉得有用:
答案 2 :(得分:2)
我找到了非常糟糕的方法来修补路线测试机器而没有找到任何方法。
我最终只是扼杀了约束'匹配?方法:
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。我喜欢在我的控制器规范中放置路由测试,就在操作的描述块之前。共享示例将被移动到一个混合到控制器规范中的模块。)
答案 3 :(得分:1)
为了让我的约束在开发模式下运行,我向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
这适用于域名约束,它对子域约束同样有效。
答案 4 :(得分:1)
这些其他答案都没有回答这个问题,至少没有任何优雅的方式。不需要模拟。
在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。
答案 5 :(得分:0)
我自己是@ RoR3的新手,但也许这个截屏会帮助你:Railscasts Subdomain
答案 6 :(得分:0)
我会测试你班级的功能,不一定是路线本身。我觉得这基本上是测试rails。
您知道如果您将类传递给约束块,那么如果您定义了.matches,它将会起作用吗?方法。所以只要测试你在那里得到了预期的逻辑。
答案 7 :(得分:0)
正如亚特·波利托上面所说,测试你想要发生的事情。
在你的约束中,你必须有某种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响应:成功,我认为。
答案 8 :(得分:-3)
rails 3中的子域名非常简单,它只是用作:
constraints :subdomain => subdomain_name do
#here comes all routes which routes under above subdomain
end