简体   繁体   中英

Why got Rspec No route matches error with Rails?

Rails files

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

Route

config/routes.rb

Rails.application.routes.draw do
  scope module: :iot do
    resources :hardwares, only: [ :index ], constraints: { format: :json }
  end

  ...
end

check routes

$ rake routes
Prefix Verb  URI Pattern                    Controller#Action
...
hardwares GET  /hardwares(.:format)         iot/hardwares#index {:format=>:json}

RSpec file

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

error

$ 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

How to write route in rspec correctly?

Edit: After looking at provided routes I think that main problem might be that you namespaced controller but not resource in routes, if that is the problem you will find solution below with some other suggestions.


Make sure you have a routing properly set in routes.rb in your case you should have something like:

namespace :iot do
  resources :hardwares
end

Then you will need to specify path instead of method name in your get request inside RSpec example:

get "/iot/hardwares", params { "test": 1 }

Let's say we have a BooksController with index action. In our routes.rb file there is resources: :books .

Provided that routes are setup correctly your example looking like this should work:

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

To make it even better you could extract path to let variable as you will be probably using it for more examples. Like this: require '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

Also you could consider changing your specs to be request specs instead of controller specs. In the release notes of RSpec you can find:

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.

You can read more on this here: http://rspec.info/blog/2016/07/rspec-3-5-has-been-released/

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM