How do you test a Rails controller method exposed as a helper_method?
That's right, helper methods are not exposed in the view tests - but they can be tested in your functional tests. And since they are defined in the controller, this is the right place to test them. Your helper method is probably defined as private
, so you'll have to use Ruby metaprogramming to call the method.
app/controllers/posts_controller.rb:
class PostsController < ApplicationController private def format_something "abc" end helper_method :format_somethingend
test/functional/posts_controller_test.rb:
require 'test_helper'class PostsControllerTest < ActionController::TestCase test "the format_something helper returns 'abc'" do assert_equal 'abc', @controller.send(:format_something) endend
This feels awkward, because you're getting around encapsulation by using send on a private method.
A better approach is to put the helper method in a module in the /controller/concerns directory, and create tests specifically just for this module.
e.g. in app controller/posts_controller.rb
class PostsController < ApplicationController include Formattableend
in app/controller/concerns/formattable.rb
module Concerns module Formattable extend ActiveSupport::Concern # adds the new hot concerns stuff, optional def format_something "abc" end end end
And in the test/functional/concerns/formattable_test.rb
require 'test_helper'# setup a fake controller to test againstclass FormattableTestController include Concerns::Formattableendclass FormattableTest < ActiveSupport::TestCase test "the format_something helper returns 'abc'" do controller = FormattableTestController.new assert_equal 'abc', controller.format_something endend
You could test @controller.view_context
from your functional/controller tests. This method is available in Rails 3, 4, and 5, as far as I can tell.
app/controllers/application_controller.rb
class ApplicationController < ActionController::Base helper_method :current_user # ...end
test/controllers/application_controller_test.rb
require 'test_helper'class ApplicationControllerTest < ActionController::TestCase test 'current_user helper exists in view context' do assert_respond_to @controller.view_context, :current_user endend
If you didn't want to test one of your controller subclasses, you could also create a test controller to verify that the method in the view_context is the same one from the controller and not from one of your view helpers.
class ApplicationControllerHelperTest < ActionController::TestCase class TestController < ApplicationController private def current_user User.new end end tests TestController test 'current_user helper exists in view context' do assert_respond_to @controller.view_context, :current_user end test 'current_user returns value from controller' do assert_instance_of User, @controller.view_context.current_user endend
Or, more likely, you'd want to be able to test the helper in the presence of a request.
class ApplicationControllerHelperTest < ActionController::TestCase class TestController < ApplicationController def index render plain: 'Hello, World!' end end tests TestController def with_routing # http://api.rubyonrails.org/classes/ActionDispatch/Assertions/RoutingAssertions.html#method-i-with_routing # http://guides.rubyonrails.org/routing.html#connecting-urls-to-code super do |set| set.draw do get 'application_controller_test/test', to: 'application_controller_test/test#index' end yield end end test 'current_user helper exists in view context' do assert_respond_to @controller.view_context, :current_user end test 'current_user returns value from controller' do with_routing do # set up your session, perhaps user = User.create! username: 'testuser' session[:user_id] = user.id get :index assert_equal user.id, @controller.view_context.current_user.id end endend