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
I have a HeartbeatController which returns a 200:
class HeartbeatController < ApplicationController
def show
render(json: { 'status': 'ok' })
end
end
It works fine with curl.
rake routes shows the route:
Prefix Verb URI Pattern Controller#Action
heartbeat GET /heartbeat(.:format) heartbeat#show
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
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With