问题描述
|
我正在使用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