Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't rspec find my no-params-required route?

Background

I am trying to port an old ActionDispatch::IntegrationTest test to rspec.

This test is currently passing:

require 'test_helper'

class HeartbeatControllerTest < ActionDispatch::IntegrationTest
  test "heartbeat" do
    get "/heartbeat"
    assert_response :success
  end
end

Controller

I have a HeartbeatController which returns a 200:

class HeartbeatController < ApplicationController
  def show
    render(json: { 'status': 'ok' })
  end
end

It works fine with curl.

Route

rake routes shows the route:

                               Prefix Verb   URI Pattern                                                                              Controller#Action
                            heartbeat GET    /heartbeat(.:format)                                                                     heartbeat#show

Spec

My test is pretty straightforward:

require 'rails_helper'

describe HeartbeatController do
  it 'succeeds' do
    get '/heartbeat'
    expect(response).to be_success
  end
end

But when I run it

Failures:

  1) HeartbeatController succeeds
     Failure/Error: get '/heartbeat'

     ActionController::UrlGenerationError:
       No route matches {:action=>"/heartbeat", :controller=>"heartbeat"}
     # ./spec/controllers/heartbeat_controller_spec.rb:5:in `block (2 levels) in <top (required)>'

Finished in 0.00718 seconds (files took 1.11 seconds to load)
1 example, 1 failure

Failed examples:

rspec ./spec/controllers/heartbeat_controller_spec.rb:4 # HeartbeatController succeeds

Questions

  • Why is this test failing?
  • What did I do wrong?
  • How could I debug this further if Stack Overflow didn't exist?
like image 569
Aaron Brager Avatar asked Dec 08 '25 08:12

Aaron Brager


1 Answers

If this is a controller spec you want to pass the name of the method and not the route.

require 'rails_helper'

describe HeartbeatController do
  it 'succeeds' do
    get :show
    expect(response).to be_success
  end
end

Controller specs don't actually drive the whole rails stack - they just create a mocked request and pass it to an instance of the controller and call the method on the controller.

The reason you are get a routing error is that ActionController::TestCase::Behavior tries to validate that a route exists for that given controller/method name combo. Thus No route matches {:action=>"/heartbeat", :controller=>"heartbeat"}.

This whole process of unit testing controllers is known to be highly flawed as you're mocking out huge portions of the framework and not actually testing what controllers do - they respond to HTTP requests. As the routing layer and middleware stack are mocked out your tests will not cover them as a real integration test would.

Both the Rails and RSpec team discourage directly testing controllers. Instead use request specs which actually drive the whole stack.

# spec/requests/heartbeats_spec.rb
require 'rails_helper'

describe 'Heartbeats', type: :request do
  describe "GET /heartbeat" do
    it 'succeeds' do
      get '/heartbeat'
      expect(response).to be_successful
    end 
  end
end
like image 100
max Avatar answered Dec 10 '25 23:12

max



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!