【问题标题】:How do you test a Rails controller method exposed as a helper_method?如何测试作为 helper_method 公开的 Rails 控制器方法?
【发布时间】:2011-01-27 17:32:09
【问题描述】:

它们似乎无法从 ActionView::TestCase 访问

【问题讨论】:

    标签: ruby-on-rails methods testing helper


    【解决方案1】:

    没错,辅助方法不会在视图测试中公开 - 但它们可以在您的功能测试中进行测试。由于它们是在控制器中定义的,因此这是测试它们的正确位置。您的辅助方法可能定义为private,因此您必须使用 Ruby 元编程来调用该方法。

    app/controllers/posts_controller.rb:

    class PostsController < ApplicationController
    
      private
    
      def format_something
        "abc"
      end
      helper_method :format_something
    end
    

    测试/功能/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
    

    【讨论】:

    • 这并没有测试 format_something 是否作为帮助程序公开。 send(:format_something) 将在没有 helper_method :format_something 的情况下工作。我正在尝试自己寻找解决方案。
    【解决方案2】:

    这感觉很尴尬,因为您通过在私有方法上使用 send 来绕过封装。

    更好的方法是将辅助方法放在 /controller/concerns 目录下的模块中,并专门为该模块创建测试。

    例如在应用控制器/posts_controller.rb

    class PostsController < ApplicationController
      include Formattable
    end
    

    在 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
    

    并且在 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
    

    【讨论】:

      【解决方案3】:

      您可以从功能/控制器测试中测试@controller.view_context。据我所知,此方法在 Rails 3、4 和 5 中可用。

      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
      

      如果您不想测试您的控制器子类之一,您还可以创建一个测试控制器来验证 view_context 中的方法是否与来自控制器的方法相同,而不是来自您的视图助手之一。

      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
      

      或者,更有可能的是,您希望能够在存在请求的情况下测试帮助程序。

      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
      

      【讨论】:

        【解决方案4】:

        我为此苦苦挣扎了一会儿,因为接受的答案实际上并没有测试该方法是否作为辅助方法公开。

        也就是说,我们可以使用#helpers 方法获取代理进行测试。

        例如:

        class FooController < ApplicationController
          private
        
          def bar
            'bar'
          end
        
          helper_method :bar
        end
        

        可以通过以下方式进行测试:

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

        【讨论】:

          【解决方案5】:

          确实不是。视图测试专门针对视图。他们不加载控制器。
          您应该模拟此方法并使其根据您的上下文返回适当的值。

          【讨论】:

          • “你应该模拟这个方法并让它返回任何合适的东西” - 我实际上想测试这个方法:-)
          • 是的,但是在视图中测试辅助方法不是合适的方法:)
          • “在视图中测试辅助方法不是合适的方法”——那么为什么 Rails 脚手架会基于 ActionView::TestCase 生成辅助测试? :-( 什么是正确的方法?我只想测试这个方法。谢谢。
          • 是的,但是这个方法主要是一个控制器方法。你应该在你的控制器/库中测试它。
          • 我的 Rails 应用程序中似乎没有 controller/lib。这是新事物吗?!
          猜你喜欢
          • 2011-05-15
          • 1970-01-01
          • 1970-01-01
          • 2017-02-02
          • 2015-05-12
          • 1970-01-01
          • 1970-01-01
          • 2011-05-09
          • 1970-01-01
          相关资源
          最近更新 更多