Reputation: 516
I am using Ruby 1.9.3 with Rails 3.2 (old, I know).
I am having trouble with one controller test. The routes work just fine, the only problem is the test.
The test is placed in project_root/test/functional/api/ubiquo/work_hours_controller_test.rb
And is defined like this:
# encoding: utf-8
require 'test_helper'
class Api::Ubiquo::WorkHoursControllerTest < ActionController::TestCase
setup :prepare
test "check_already_logged_in_ubiquo: error if not logged in" do
get :check_already_logged_in_ubiquo, format: :json
assert_response :unauthorized
end
def prepare
# I tried both specifying the controller like this and also letting Rails do it
@controller = Api::Ubiquo::WorkHoursController.new
end
end
The controller is placed in project_root/app/controllers/api/ubiquo/work_hours_controller.rb
and is defined like this. (I simplified it to debug)
class Api::Ubiquo::WorkHoursController < Api::Ubiquo::BaseController
def check_already_logged_in_ubiquo
respond_to do |format|
format.json { render json: { message: 'Not logged in' }, status: :unauthorized }
end
end
end
rellevant part of routes.rb
:
scope :path => "api", :format => 'json' do
get 'ubiquo/check_already_logged_in_ubiquo', to: 'api/ubiquo/work_hours#check_already_logged_in_ubiquo'
# I also tried this:
# namespace :ubiquo do
# get 'check_already_logged_in_ubiquo', to: 'api/ubiquo/work_hours#check_already_logged_in_ubiquo'
# end
end
rake routes
returns the correct route (which works when running the app)
ubiquo_check_already_logged_in_ubiquo GET /api/ubiquo/check_already_logged_in_ubiquo(.:format) api/ubiquo/work_hours#check_already_logged_in_ubiquo {:format=>"json"}
The error I get is:
ActionController::RoutingError: No route matches {:format=>:json, :controller=>"api/ubiquo/work_hours", :action=>"check_already_logged_in_ubiquo"}
I have also tried defining the test as class CustomWorkHoursControllerTest < ActionController::TestCase
(without the modules Api::Ubiquo) and then the error does not fire but request just returns 406. In no case the debugger reaches the controller.
All other controller tests are working just fine, including those in /api, just not those in /api/ubiquo.
I really don't know what else to try.
Update I saw that test_helper was doing somethings I was not aware of, I removed those and now I get
Expected response to be a <:unauthorized>, but was <406>
still not entering the controller.
Some info I get while debugging (which looks just fine): in the request @env:
action_dispatch.request.parameters => {ActiveSupport::HashWithIndifferentAccess} {action: check_already_logged_in_ubiquo, controller: api/ubiquo/work_hours, format: json}
Upvotes: 0
Views: 50
Reputation: 516
It turned out it was all due to the controller in question inheriting from another controller with a before_filter
that renders in formats :js, :xml, :atom, :rss, or :html when not logged in before it could ever reach my action. And since :json is not among the formats in the filter, it fired :not_acceptable 406.
It did work when I called it normally because I was logged in...
Upvotes: 0
Reputation: 102249
This test is the old and depreachiated functional style tests. Don't use them.
What they do is basically just instanciate an instance of your controller with a faked request and then call the method on the controller. Controllers are Rack apps and cannot function without it which is why @controller = Api::Ubiquo::WorkHoursController.new
breaks.
The router isn't even actually used. The test just tries to find something vaguely correct in the route set by searching by controller, action and format which is extremely error prone.
Even back in Rails 3.0.2 you have ActionDispatch::IntegrationTest which can be used instead which is a future proof approach.
# encoding: utf-8
require 'test_helper'
module Api
module Ubiquo
class WorkHoursControllerTest < ActionDispatch::IntegrationTest
test "check_already_logged_in_ubiquo: error if not logged in" do
get 'api/ubiquo/check_already_logged_in_ubiquo', format: :json
assert_response :unauthorized
end
end
end
end
You can declare the routes in a less clunky way with:
namespace :api, :format => 'json' do
namespace :ubiquo do
resources :work_hours, :only => [] do
get :check_already_logged_in_ubiquo
end
end
end
namespace :api
is just shorthand for scope '/api', module: :api
.
You're also misusing the scope resolution operator (::
) for declaring nested classes. This is not an equivilent short hand syntax. It doesn't actually set the module nesting correctly and leads to wierd constant lookups as well as issues with the classic autoloader since it (ab)uses constant_missing
.
Declare namespaces explicitly.
I have also tried defining the test as class CustomWorkHoursControllerTest < ActionController::TestCase (without the modules Api::Ubiquo) and then the error does not fire but request just returns 406. In no case the debugger reaches the controller.
ActionController::TestCase
uses a set of heuristics to guess the name of the class under test based on the name of the test class including the modules it is nested in. While nothing here is obviously wrong you're this can be overridden by using the tests
method.
require 'test_helper'
class Api::Ubiquo::WorkHoursControllerTest < ActionController::TestCase
tests Foo::Bar:BazController
test "check_already_logged_in_ubiquo: error if not logged in" do
get :check_already_logged_in_ubiquo, format: :json
assert_response :unauthorized
end
end
Upvotes: 1