开发者

How do you test a Rails controller method exposed as a helper_method?

开发者 https://www.devze.com 2022-12-22 19:42 出处:网络
They don\'t seem to be accessible from ActionVie开发者_StackOverflow社区w::TestCaseThat\'s right, helper methods are not exposed in the view tests - but they can be tested in your functional tests. An

They don't seem to be accessible from ActionVie开发者_StackOverflow社区w::TestCase


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_something
end

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)
  end
end


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 Formattable
end

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 against
class FormattableTestController
  include Concerns::Formattable
end

class FormattableTest < ActiveSupport::TestCase

 test "the format_something helper returns 'abc'" do
    controller = FormattableTestController.new
    assert_equal 'abc', controller.format_something
  end

end


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
  end
end

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
  end
end

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
  end
end


I've struggled with this for a bit, because the accepted answer didn't actually test whether the method was exposed as a helper method.

That said, we can use the #helpers method to get a proxy for testing.

For example:

class FooController < ApplicationController
  private

  def bar
    'bar'
  end

  helper_method :bar
end

Can be tested with:

require 'test_helper'

class FooControllerTest < ActionController::TestCase
  test 'bar is a helper method' do
    assert_equal 'bar', @controller.helpers.bar
  end
end


Indeed they're not. The view tests are specifically for the views. They don't load the controllers.
You should mock this method and make it return whatever is appropriate depending of your context.

0

精彩评论

暂无评论...
验证码 换一张
取 消