为什么 Rspec No route matches error with Rails?
Why got Rspec No route matches error with Rails?
Rails 个文件
app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
# ...
end
app/controllers/api_application_controller.rb
class ApiApplicationController < ActionController::API
# ...
end
app/controllers/iot_application_controller.rb
class IotApplicationController < ApiApplicationController
# ...
end
app/controllers/iot/hardwares_controller.rb
class Iot::HardwaresController < IotApplicationController
def index
# ...
end
end
路线
config/routes.rb
Rails.application.routes.draw do
scope module: :iot do
resources :hardwares, only: [ :index ], constraints: { format: :json }
end
...
end
检查路线
$ rake routes
Prefix Verb URI Pattern Controller#Action
...
hardwares GET /hardwares(.:format) iot/hardwares#index {:format=>:json}
RSpec 文件
spec/controllers/iot/hardwares_controller.rb
require 'rails_helper'
RSpec.describe Iot::HardwaresController, type: :controller do
describe "GET #index" do
context "with invalid params" do
it "renders a JSON response with errors" do
get :index, params: { "test": 1 }
expect(response).to have_http_status(:bad_request)
end
end
end
end
错误
$ rspec .
Iot::HardwaresController
GET #index
with invalid params
renders a JSON response with errors (FAILED - 1)
Failures:
1) Iot::HardwaresController GET #index with invalid params renders a JSON response with errors
Failure/Error: get :index, params: {"test": 1}
ActionController::UrlGenerationError:
No route matches {:action=>"index", :controller=>"iot/hardwares", :test=>1}
# ./spec/controllers/iot/hardwares_controller.rb:17:in `block (4 levels) in <top (required)>'
Finished in 0.01547 seconds (files took 6.79 seconds to load)
1 example, 1 failure
如何在rspec中正确写路由?
编辑:在查看提供的路由后,我认为主要问题可能是您命名空间控制器而不是路由中的资源,如果这是问题,您将在下面找到解决方案和其他一些建议。
确保在 routes.rb
中正确设置了路由 在你的情况下你应该有类似的东西:
namespace :iot do
resources :hardwares
end
然后您需要在 RSpec 示例中的 get
请求中指定 path
而不是方法名称:
get "/iot/hardwares", params { "test": 1 }
假设我们有一个 BooksController
和 index
动作。在我们的 routes.rb
文件中有 resources: :books
.
只要路由设置正确,您的示例应该可以正常工作:
require 'rails_helper'
RSpec.describe Iot::HardwaresController, type: :controller do
describe "GET #index" do
context "with invalid params" do
it "renders a JSON response with errors" do
get "/iot/hardwares", params: { "test": 1 }
expect(response).to have_http_status(:bad_request)
end
end
end
end
为了让它变得更好,您可以提取 let 变量的路径,因为您可能会在更多示例中使用它。像这样:
需要 'rails_helper'
RSpec.describe Iot::HardwaresController, type: :controller do
describe "GET #index" do
let(:path) { "/iot/hardwares" }
context "with invalid params" do
it "renders a JSON response with errors" do
get path, params: { "test": 1 }
expect(response).to have_http_status(:bad_request)
end
end
end
end
您也可以考虑将规格更改为请求规格而不是控制器规格。在 RSpec 的发行说明中,您可以找到:
For new Rails apps: we don't recommend adding the rails-controller-testing gem to your application. The official recommendation of the Rails team and the RSpec core team is to write request specs instead. Request specs allow you to focus on a single controller action, but unlike controller tests involve the router, the middleware stack, and both rack requests and responses. This adds realism to the test that you are writing, and helps avoid many of the issues that are common in controller specs. In Rails 5, request specs are significantly faster than either request or controller specs were in rails 4, thanks to the work by Eileen Uchitelle1 of the Rails Committer Team.
您可以在此处阅读更多相关信息:http://rspec.info/blog/2016/07/rspec-3-5-has-been-released/
Rails 个文件
app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
# ...
end
app/controllers/api_application_controller.rb
class ApiApplicationController < ActionController::API
# ...
end
app/controllers/iot_application_controller.rb
class IotApplicationController < ApiApplicationController
# ...
end
app/controllers/iot/hardwares_controller.rb
class Iot::HardwaresController < IotApplicationController
def index
# ...
end
end
路线
config/routes.rb
Rails.application.routes.draw do
scope module: :iot do
resources :hardwares, only: [ :index ], constraints: { format: :json }
end
...
end
检查路线
$ rake routes
Prefix Verb URI Pattern Controller#Action
...
hardwares GET /hardwares(.:format) iot/hardwares#index {:format=>:json}
RSpec 文件
spec/controllers/iot/hardwares_controller.rb
require 'rails_helper'
RSpec.describe Iot::HardwaresController, type: :controller do
describe "GET #index" do
context "with invalid params" do
it "renders a JSON response with errors" do
get :index, params: { "test": 1 }
expect(response).to have_http_status(:bad_request)
end
end
end
end
错误
$ rspec .
Iot::HardwaresController
GET #index
with invalid params
renders a JSON response with errors (FAILED - 1)
Failures:
1) Iot::HardwaresController GET #index with invalid params renders a JSON response with errors
Failure/Error: get :index, params: {"test": 1}
ActionController::UrlGenerationError:
No route matches {:action=>"index", :controller=>"iot/hardwares", :test=>1}
# ./spec/controllers/iot/hardwares_controller.rb:17:in `block (4 levels) in <top (required)>'
Finished in 0.01547 seconds (files took 6.79 seconds to load)
1 example, 1 failure
如何在rspec中正确写路由?
编辑:在查看提供的路由后,我认为主要问题可能是您命名空间控制器而不是路由中的资源,如果这是问题,您将在下面找到解决方案和其他一些建议。
确保在 routes.rb
中正确设置了路由 在你的情况下你应该有类似的东西:
namespace :iot do
resources :hardwares
end
然后您需要在 RSpec 示例中的 get
请求中指定 path
而不是方法名称:
get "/iot/hardwares", params { "test": 1 }
假设我们有一个 BooksController
和 index
动作。在我们的 routes.rb
文件中有 resources: :books
.
只要路由设置正确,您的示例应该可以正常工作:
require 'rails_helper'
RSpec.describe Iot::HardwaresController, type: :controller do
describe "GET #index" do
context "with invalid params" do
it "renders a JSON response with errors" do
get "/iot/hardwares", params: { "test": 1 }
expect(response).to have_http_status(:bad_request)
end
end
end
end
为了让它变得更好,您可以提取 let 变量的路径,因为您可能会在更多示例中使用它。像这样: 需要 'rails_helper'
RSpec.describe Iot::HardwaresController, type: :controller do
describe "GET #index" do
let(:path) { "/iot/hardwares" }
context "with invalid params" do
it "renders a JSON response with errors" do
get path, params: { "test": 1 }
expect(response).to have_http_status(:bad_request)
end
end
end
end
您也可以考虑将规格更改为请求规格而不是控制器规格。在 RSpec 的发行说明中,您可以找到:
For new Rails apps: we don't recommend adding the rails-controller-testing gem to your application. The official recommendation of the Rails team and the RSpec core team is to write request specs instead. Request specs allow you to focus on a single controller action, but unlike controller tests involve the router, the middleware stack, and both rack requests and responses. This adds realism to the test that you are writing, and helps avoid many of the issues that are common in controller specs. In Rails 5, request specs are significantly faster than either request or controller specs were in rails 4, thanks to the work by Eileen Uchitelle1 of the Rails Committer Team.
您可以在此处阅读更多相关信息:http://rspec.info/blog/2016/07/rspec-3-5-has-been-released/