如何测试作为 helper_method 公开的 Rails 控制器方法?

发布于 2024-08-25 13:42:41 字数 38 浏览 7 评论 0原文

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

They don't seem to be accessible from ActionView::TestCase

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

你是年少的欢喜 2024-09-01 13:42:41

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

应用程序/控制器/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

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
横笛休吹塞上声 2024-09-01 13:42:41

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

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

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

class PostsController < ApplicationController
  include Formattable
end

中的应用程序/控制器/concerns/formattable.rb

  module Concerns
    module Formattable
      extend ActiveSupport::Concern # adds the new hot concerns stuff, optional

      def format_something
        "abc"
      end
    end
  end

和在测试/功能/关注/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

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
是你 2024-09-01 13:42:41

您可以从功能/控制器测试中测试@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

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
<逆流佳人身旁 2024-09-01 13:42:41

我在这个问题上挣扎了一段时间,因为接受的答案实际上并没有测试该方法是否作为辅助方法公开。

也就是说,我们可以使用 #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

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
站稳脚跟 2024-09-01 13:42:41

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

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文