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

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

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

应用程序/控制器/ posts_controller.rb:

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

测试/function/ 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 

这感觉很尴尬,因为你通过在私有方法上使用send来解决封装问题。

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

例如在app controller / 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 

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

应用程序/控制器/ application_controller.rb

 class ApplicationController < ActionController::Base helper_method :current_user # ... end 

测试/控制器/ 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 

如果您不想测试某个控制器子类,还可以创建一个测试控制器来validationview_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 

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

我对此有点挣扎,因为接受的答案实际上没有测试该方法是否作为辅助方法公开。

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