How do you test a Rails controller method exposed as a helper_method? How do you test a Rails controller method exposed as a helper_method? ruby-on-rails ruby-on-rails

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