路由规范是否支持重定向路由?[RSpec]

31
在深入研究此问题后,我对文档的理解和我的结果之间陷入了僵局。
根据https://www.relishapp.com/rspec/rspec-rails/v/2-8/docs/routing-specs/route-to-matcher的说明,我们应该能够编写以下内容:
#rspec-rails (2.8.1)
#rspec (>= 1.3.1)
#rspec-core (~> 2.8.0)

# routing spec
require "spec_helper"

describe BusinessUsersController do
  describe "routing" do
    it "routes to some external url" do
      get("/business_users/7/external_url").should route_to("http://www.google.com")
    end
  end
end

# routes.rb
BizeebeeBilling::Application.routes.draw do

  resources :business_users do
    member do
      get "external_url" => redirect("http://www.google.com")
    end
  end
end

运行此规范将产生以下结果: 失败:

  1) BusinessUsersController routing routes to some external url
     Failure/Error: assert_routing "/business_users/7/external_url", "http://www.google.com"
     ActionController::RoutingError:
       No route matches "/business_users/7/external_url"
     # ./spec/routing/business_users_routing_spec.rb:19:in `block (3 levels) in <top (required)>'

我在任何地方都找不到关于这个具体问题的报告。
补充细节:手动测试时,路由器可以完美地解析。
5个回答

51

路由规范/测试专注于测试特定控制器和操作(以及可能的一些参数)是否映射到路由。

我深入研究了Rails和Journey的内部机制。RSpec和Rails(基本上省略了一些细节)使用Rails.application.routes.recognize_path来回答“这个路由可用吗?”的问题。

例如:

$ rails console
> Rails.application.routes.recognize_path("/business_users/1", method: "GET")
 => {:action=>"show", :controller=>"business_users", :id=>"1"}

然而,在/business_users/1/external_url的另一端没有控制器。实际上,为了执行重定向,Rails创建了一个ActionDispatch::Routing::Redirect的实例,这是一个小的Rack应用程序。没有Rails控制器被涉及。你基本上挂载了另一个Rack应用程序来执行重定向。

为了测试重定向,我建议使用请求规范(位于spec/requests文件中)。像这样:

require "spec_helper"

describe "external redirection" do
  it "redirects to google.com" do
    get "/business_users/1/external_url"
    response.should redirect_to("http://www.google.com")
  end
end

这将隐式地测试路由,并允许您针对重定向进行测试。


1
这很好理解,但是当我尝试时遇到了一个问题。在我的Rspec before块中,我加载了seeds.rb,因为即使在测试中也需要一些基线数据。但由于重定向使用了一个微小的Rack应用程序,加载seeds.rb会失败,对于任何模型都会出现“找不到表”的错误,可能是因为非Rails Rack应用程序不使用ActiveRecord。所以我没有好的方法来进行重定向路由的回归测试,虽然它们在应用程序中可以工作,但我无法让测试通过。 :-( - Armando Fox
如果您不喜欢“should”语法,可以使用以下代码:expect(response).to redirect_to("http://www.google.com") - Dave Morse

25

Andy Lindeman给出了正确的答案。不过,你不必将规范放在spec/requests目录下,你可以将其放在spec/routing目录下,并使用元数据"type"进行明确:describe 'my route', type: :request do


我尝试过这个,但仍然无法在规范的上下文中找到响应对象。 - Shyam Habarakada
在调试了一下之后,看起来rspec不允许我覆盖spec/routing路径中的规范类型。如果我将其移动到spec/request或spec/api之外并放置在其中,它就可以正常工作。我会在rspec-rails上开一个问题来解决这个问题。 - Shyam Habarakada

9
我遇到了一个类似的情况,我试图测试一系列路由,其中一些应该重定向,而另一些则不需要。我希望将它们保留在单个路由规范中,因为这是最合适的分组方式。我尝试使用describe: 'my route', type: request,但发现这样做行不通。但是,您可以在spec上下文中包含RSpec::Rails::RequestExampleGroup,以便访问请求规范方法。类似如下内容:
describe "My Routes" do
  context "Don't Redirect" do
    it "gets URL that doesn't redirect" do
      get("business_users/internal_url").should route_to(controller: "business_users", action: "internal_url_action")
    end
  end

  context "Redirection" do
    include RSpec::Rails::RequestExampleGroup
    it "redirects to google.com" do
      get "/business_users/1/external_url"
      response.should redirect_to("http://www.google.com")
    end
  end
end

-1

测试外部重定向的最简单方法是使用集成测试:

  test "GET /my_page redirects Google" do
    get "/my_page"
    assert_redirected_to "https://google.com"
  end

你的测试需要放在test/integration目录或者等价的集成测试目录下。


在 RSpec 中,这将是一个请求规范。 - nruth

-3

redirect_to匹配器在路由规范中不可用。此外,错误不在匹配器中,而是在明确定义在routes.rb中的路线在运行测试时未被捕获。另外,当手动测试时,路线本身可以完美地工作。 - zealoushacker
3
如果它不是一个控制器规范,那么为什么要以“describe BusinessUsersController”开头? - Nick Colgan
1
你说得没错。但是那些都是自动生成的。我想那是一个完全不同的问题 :( - zealoushacker

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接